├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .settings.xml ├── .travis.yml ├── LICENSE ├── README.md ├── RELEASE.md ├── header.txt ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src ├── main │ ├── java │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── jdbc │ │ │ ├── ConnectionInfo.java │ │ │ ├── JdbcTracing.java │ │ │ ├── JdbcTracingUtils.java │ │ │ ├── TracingCallableStatement.java │ │ │ ├── TracingConnection.java │ │ │ ├── TracingDataSource.java │ │ │ ├── TracingDriver.java │ │ │ ├── TracingPreparedStatement.java │ │ │ ├── TracingStatement.java │ │ │ └── parser │ │ │ ├── AS400URLParser.java │ │ │ ├── AbstractMatcherURLParser.java │ │ │ ├── AbstractURLParser.java │ │ │ ├── ConnectionURLParser.java │ │ │ ├── DB2URLParser.java │ │ │ ├── H2URLParser.java │ │ │ ├── MariadbURLParser.java │ │ │ ├── MysqlURLParser.java │ │ │ ├── OracleURLParser.java │ │ │ ├── PostgreSQLURLParser.java │ │ │ ├── SqlServerURLParser.java │ │ │ ├── URLLocation.java │ │ │ └── URLParser.java │ └── resources │ │ └── META-INF │ │ └── services │ │ └── java.sql.Driver └── test │ ├── java │ └── io │ │ └── opentracing │ │ └── contrib │ │ └── jdbc │ │ ├── HibernateTest.java │ │ ├── JdbcTest.java │ │ ├── JdbcTracingUtilsTest.java │ │ ├── SpringTest.java │ │ ├── TestUtil.java │ │ ├── TracingDataSourceTest.java │ │ ├── TracingDriverTest.java │ │ └── parser │ │ ├── AS400URLParserTest.java │ │ ├── DB2URLParserTest.java │ │ ├── OracleURLParserTest.java │ │ ├── SqlServerURLParserTest.java │ │ └── URLParserTest.java │ └── resources │ └── META-INF │ └── persistence.xml └── travis └── publish.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .metadata/ 3 | .recommenders/ 4 | .settings/ 5 | target/ 6 | *.iml 7 | .classpath 8 | .project -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opentracing-contrib/java-jdbc/6722745cbbd61fce8550dd8e1e0d8a828a1e7a3c/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip -------------------------------------------------------------------------------- /.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 21 | 22 | 23 | sonatype 24 | ${env.SONATYPE_USER} 25 | ${env.SONATYPE_PASSWORD} 26 | 27 | 28 | bintray 29 | ${env.BINTRAY_USER} 30 | ${env.BINTRAY_KEY} 31 | 32 | 33 | jfrog-snapshots 34 | ${env.BINTRAY_USER} 35 | ${env.BINTRAY_KEY} 36 | 37 | 38 | github.com 39 | ${env.GH_USER} 40 | ${env.GH_TOKEN} 41 | 42 | 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | 3 | language: java 4 | jdk: 5 | - oraclejdk8 6 | 7 | cache: 8 | directories: 9 | - $HOME/.m2/repository 10 | 11 | before_install: 12 | # allocate commits to CI, not the owner of the deploy key 13 | - git config user.name "opentracingci" 14 | - git config user.email "opentracingci+opentracing@googlegroups.com" 15 | 16 | # setup https authentication credentials, used by ./mvnw release:prepare 17 | - git config credential.helper "store --file=.git/credentials" 18 | - echo "https://$GH_TOKEN:@github.com" > .git/credentials 19 | 20 | install: 21 | # Override default travis to use the maven wrapper 22 | - ./mvnw install -DskipTests=true -Dmaven.javadoc.skip=true -B -V 23 | 24 | script: 25 | - ./travis/publish.sh 26 | 27 | branches: 28 | except: 29 | - /^[0-9]/ 30 | 31 | after_success: 32 | - mvn jacoco:report coveralls:report 33 | 34 | env: 35 | global: 36 | # Ex. travis encrypt BINTRAY_USER=your_github_account 37 | - secure: "hVicpP51WpEErSDy8ThcZ8zJhrQ/+8Mg9NiGT6IBxAuWDH6jQ2BIyYJ5oc/h7TRW2CYiAzBe0Qzd38Ifpw5gH6WHCK1qJiAuO+qjvNh5h5TeVaKUJHs2JPPHYM0WZMMQKpPTmcNi+EkozVTsef5hoX+tv0/WEVwCqJvRA6xelL37/kaTxmZJDq570RG6fFmAsfQFuN+PvFn1SutvIXkseetyKXtr+KvPaLniomOxdmVvzU60RMhxwaacmlRzu1D9uzGEDPmagW8iDB/byuBlZAyQVMMusZwbHSxqH471hNCU/PEg8NysmR0ZuRSonFOUu5RoERz9tLfUTV3PHgnNj/ZqlzABYfVuCIsB4led3uaEgb+en3fbWPFLr4YvTe2pqH7k7XNJELqvgfC2cCBu1cEtPq0bIZiDvz9i+qqUxUPrzkku2XKGf58bJz3UKmLECAC3VEMYE+z/PdjBD6FXK5ynfeWJH2q0MZqiVSqv4XSJn1BnOabINqy2xxnWk4EkfZQhqT70HPZ8AQEppgwDbtqCBdoD3ySNipq7FGJ/hGpmUqKh9E7JBSOLjyyix1ExKYlqglFAYOSgQOHSuVMFBi1GnbFzfKX22dwrN2gJHAx7FezEIxlbM6+ZBpC3DHjTaFlRAcAlE6Ci5KNkv1VnjtooijTPGawDNranRLVnlds=" 38 | # Ex. travis encrypt BINTRAY_KEY=xxx-https://bintray.com/profile/edit-xxx --add 39 | - secure: "eyYuOFs7rnWnLnZFrkPsY9fuxPQq9W192vCoEOHzqtfkOHNFJkqwx1H1CWviZHbLVZl7qn0MpI/d3cQ93KgoKHJd1nRKEjBmm32bFg8BGXFhQA0r2/ylNjcZO7sZbJd2L+JK8U+O7hnQF+FJ5Gftn9aIRBxIiV/oJuelHWXEqFLv0Zgh+yVSc/aPzianAv9BcczpGGcO6K64gNMvg1HsIpK2VDw4DMyXkHFmw48BIvzDKgTVFkMKuy2UBSg2O1rqUCfAeoVn4VhF3R4Mrm+NyeCVGkmoL++ZIW9cp7hLsWiLac6AGhdujHEnUhJDd/KtiOoYQR0+perb65tuW8chPW4oul4ije2IKXlZZmv20jTev2N1+rtAmETexVn8EVdVLj90YBV1mjGTQl4tWRfxjQXFcwk9J4g4Nfce/x8DDNxygAB6KSNq1xaoZi+omQ3ELl7uN4et2ZqgJ7m+wapDt09B0An2JgrNKXGqzxZJaDX4gkPWPCtBoaycByrElQokA6abzI5PAFeTdxJ1mpeq8oZo+8sHwnYB0ml3D/P01mNOlU13sxi1nixLrO5RDdHM5tq3Cs/eZQjePu06taOEzCm6APX9FFbAq7AJbGnPjCk8g+7v8mBj/Bwo1qIyIN7LR7tRez1n+FqTPJPvmEI21YKhPOV3dNjDY+dLbhUbAaY=" 40 | # Ex. travis encrypt GH_TOKEN=XXX-https://github.com/settings/tokens-XXX --add 41 | - secure: "mvvdjwFUe1D7aRPJCFb2oBiy+pTaYp5p/CXRLRJpq/Ap3aZ7N1GC4wjuWQKG0zR7cRnWX2OrtyQjR4q9iBT7nkrfSRZnNlu1zLQMrfpijIGCwC10wr/nuz/rtH0BjkozHHnDpedHDUp0P/WAWB99QSmxyKauvcShFQ2ceEAdZjuyVRKkWIcE9PgRjKIPc5TjVK9dZRHg/r65P5Mha2r3H5Rg7AfBLQebZqwMcR3BzilQAeUyUwuajNJMthzB76s3vYiAh4AbMJ9eM71VWc3Qtygl9U0xGKFSKuMkoPJIV7KYCoM9CKBmUz8uOGmBZyeYBy4FPXLvItAjJ5Oato9ujAr/sHk1044QT7rriRjSu+yNZeUwLP/uHLcWFHzYsSdIyY+S55BXPk5sg+ZFFZl/Lj+fJizAzQvZC+MgTVIhIIRE06fCA1qKwkMjPeRnGtUJVDw0NVJdTTs28J6l8EWbgOOuUJZaJO2pKcFR2QZfzh90ATVnBKH4UMhQMoLVklqUp2x3DNCamgrw/qa+vMk+PMnOQrPiOBKvu9qqwLVpiU0iNjvNUZrH1cF0WcGd4mqlqYbJ57shs1EVw/JfClrPaf6sYg26GJAfS+W2Nvr7FVT6OIeXAn2XKVrV18H43p+G3UZ3FyoXVnnWwkeXlpp2HtcFa5S53lrAvWdbUBmUsfQ=" 42 | # Ex. travis encrypt SONATYPE_USER=your_sonatype_account 43 | - secure: "sdpWjltkPcEBsBHuuFgklG5+U2ZHZR0ea059jQwJtFHLBIBxN3hR0kWXki/VhZ3nT2j6C5gsYA6um6A8gRUIiYeHVWfEPQXDll677FIb3Og9pxblYSaZ4fxplQmqqr6bf52lojMFFG1VdTH7BXaVq0VIgphp4SKcmVZABuFPXFWfZ83UmdXE8zAkL9FJgAQkGi4z6qrEq4HGeUosbuSeH2tM3BYpYZRWwHgAVMTjAkL8NDcyawUJ4ZQWRwXUezmXTXsRjRA5u5TksKNlXPmOpffcYdTTpDH+FNbwjLTNJuy6C0/E2rVMCUgVYD3fQ/pcobp5csJl7VluLTSTIHfpGGCcxGJjTHZQcVlmuPulTNDcJtjEEnX1YczkVS+w1x3/j9Qlpj69YYN9KEee4mmSJlCDvZLSHhSoAuWMiry8RgHKiIlrXR2/75tgBQ/B23UBvC10fhXKdtKiVYjdCpBhHlMuLca7VAROtvzgneMf6c5kiVwspwz8TeOgC8mkL44zK4yBgT5fUExhYV4ModrcuiShgpWvjw/F5F8JaRvIDDaBE7L0NPO0w6lly+Ps6ELNXJzetWFOXlT8ti0YWnOcWfylE3SQfppySFBS6f3vv8aqEuu/RVWY7KI5NcH8iCKSkaS8YkNshv+of7qzoMMQx5mkAAQfT03Y3ozxY+r+9nE=" 44 | # Ex. travis encrypt SONATYPE_PASSWORD=your_sonatype_password 45 | - secure: "GaDkVIdmFFJcV1qQF8KnUYritiIco1BFzYVRxxlA14qOJPgEA7XXSgbLWFsZR0tuL+z3ulfP5EvDYo8L+gP8YSrESVZiLCz3fDuqTbpWtFzZSvJuoyyffUHqpsDqT7SbyzzrFV5bEG1KI+jHlyiN6qc4iYPO/ce1ADzmz1sSKb9jpTlNht8ErWyScwScloPWgkG3s1oDVXKCHSRBUEa6FrtbNhg3jMp6dgB7L9FNXM91L7oF/ORyAsK3NgL2p3xOBfLNBbIOhpPD9GY0xC/6edzHUUirE/amSgT0w/mZws3RFRhExU+Q8sKC2PCpUvi2lYUpRSKc84Sq3Bail6EqQiaGnbQHlOKtlBMDosY3bQaqOZGKhWMoLDdPFwsKWtAmfLZD94q4ANwQJ+6QjJ5HV+0+O/bGNfu5CgAwGOeD5GyL1BG2el+3Y2WvLXz0Rhz6SSXRZr/x77hEu1dI7dRVGnb5w2DheSQDFrcCLxFmaZ9BBharfua2pGpipob9zpvzfIIc448j5UeOb+YIuQasbzPEwJfG/E2PTVe0mYhALbEPGYv/Ru09g2IKK1RLw0us7ivspMcob+O2Y8WWzVkHRGiZ++AQBJIIKJgtXsqeQU79PxFVRb23IucND01dMlZm+ZVjPhHhbQ666y2VPf2n79k/U5lMtMEZ/2YVZCs0lpc=" 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Released Version][maven-img]][maven] [![Apache-2.0 license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 2 | 3 | # OpenTracing JDBC Instrumentation 4 | 5 | OpenTracing instrumentation for JDBC. 6 | 7 | ## Installation 8 | 9 | pom.xml 10 | 11 | ```xml 12 | 13 | io.opentracing.contrib 14 | opentracing-jdbc 15 | VERSION 16 | 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Non-interceptor 22 | 23 | > Tracing for JDBC connections of URLs starting with `"jdbc:tracing:"`. 24 | 25 | 1. Activate tracing for JDBC connections by adding `tracing` to the JDBC url: 26 | 27 | _jdbc:**tracing**:h2:mem:test_ 28 | 29 | To trace calls with active `Span`s only, set property `traceWithActiveSpanOnly=true`. 30 | 31 | _jdbc:**tracing**:h2:mem:test?**traceWithActiveSpanOnly=true**_ 32 | 33 | To ignore specific queries (such as health checks), use the 34 | property `ignoreForTracing="SELECT 1"`. Double quotes can be escaped with `\`. 35 | 36 | `SELECT * FROM \"TEST\"`
The property can be repeated for multiple statements. 37 | 38 | 2. Set driver class to `io.opentracing.contrib.jdbc.TracingDriver`. 39 | 40 | ```java 41 | Class.forName("io.opentracing.contrib.jdbc.TracingDriver"); 42 | ``` 43 | 44 | or 45 | 46 | ```java 47 | io.opentracing.contrib.jdbc.TracingDriver.load(); 48 | ``` 49 | 50 | 3. Instantiate tracer and register it with GlobalTracer. 51 | 52 | ```java 53 | // Instantiate tracer 54 | Tracer tracer = ... 55 | 56 | // Register tracer with GlobalTracer 57 | GlobalTracer.register(tracer); 58 | 59 | ``` 60 | 61 | ### Interceptor 62 | 63 | > Tracing for all JDBC connections without modifying the URL. 64 | 65 | In "interceptor mode", the `TracingDriver` will intercept calls 66 | to `DriverManager.getConnection(url,...)` for all URLs. The `TracingDriver` provides connections to 67 | the `DriverManager` that are instrumented. Please note that the `TracingDriver` must be registered 68 | before the underlying driver, It's recommended to turn on "interceptor mode" in the first place. 69 | 70 | For standalone applications: 71 | 72 | ```java 73 | public static void main(String[] args) { 74 | io.opentracing.contrib.jdbc.TracingDriver.setInterceptorMode(true); 75 | // some jdbc operation here 76 | } 77 | 78 | ``` 79 | 80 | For web applications: 81 | 82 | ```java 83 | public void contextInitialized(ServletContextEvent event) { 84 | io.opentracing.contrib.jdbc.TracingDriver.setInterceptorMode(true); 85 | } 86 | ``` 87 | 88 | Or call `TracingDriver.ensureRegisteredAsTheFirstDriver()` along 89 | with `TracingDriver.setInterceptorMode(true)` at any place, Please note driver like Oracle JDBC may 90 | fail since it's destroyed forever after deregistration. 91 | 92 | The `withActiveSpanOnly` and `ignoreStatements` properties for "interceptor mode" can be configured 93 | with the `TracingDriver` via: 94 | 95 | ```java 96 | // Set withActiveSpanOnly=true 97 | TracingDriver.setInterceptorProperty(true); 98 | ``` 99 | 100 | and 101 | 102 | ```java 103 | // Set ignoreStatements={"CREATE TABLE ignored (id INTEGER, TEST VARCHAR)"} 104 | TracingDriver.setInterceptorProperty(Collections.singleton("CREATE TABLE ignored (id INTEGER, TEST VARCHAR)")); 105 | ``` 106 | 107 | ### Hibernate 108 | 109 | ```xml 110 | 111 | 112 | io.opentracing.contrib.jdbc.TracingDriver 113 | jdbc:tracing:mysql://localhost:3306/test 114 | ... 115 | 116 | ... 117 | 118 | ``` 119 | 120 | ### JPA 121 | 122 | ```xml 123 | 124 | 125 | 126 | 127 | ... 128 | 129 | 130 | ``` 131 | 132 | ### Spring 133 | 134 | For dbcp2: 135 | 136 | ```xml 137 | 138 | 139 | 140 | ... 141 | 142 | 143 | ``` 144 | 145 | ### Spring Boot 2 146 | 147 | For Hikari (Postgresl): 148 | 149 | ```properties 150 | ### Spring JPA Datasource Connection 151 | spring.datasource.username=postgres 152 | spring.datasource.password=XXXXX 153 | spring.datasource.hikari.driverClassName=io.opentracing.contrib.jdbc.TracingDriver 154 | spring.datasource.hikari.jdbcUrl=jdbc:tracing:postgresql://localhost:5432/my_app_db 155 | 156 | ``` 157 | 158 | Configuration Bean: 159 | 160 | ```java 161 | 162 | @Component 163 | public class OpenTracingConfig { 164 | 165 | @Bean 166 | public io.opentracing.Tracer jaegerTracer() { 167 | io.opentracing.contrib.jdbc.TracingDriver.load(); 168 | return new Configuration("my_app").getTracer(); 169 | } 170 | } 171 | 172 | ``` 173 | 174 | ## Slow Query 175 | 176 | Span is marked by tag `slow=true` if duration exceed `slowQueryThresholdMs`. 177 | `slowQueryThresholdMs` defaults to `0` which means disabled, can be enabled in two ways: 178 | 179 | 1. Passing system property, E.g. `-Dio.opentracing.contrib.jdbc.slowQueryThresholdMs=100` 180 | 2. Modify value by code, E.g. `io.opentracing.contrib.jdbc.JdbcTracing.setSlowQueryThresholdMs(100)` 181 | 182 | ## Fast Query 183 | 184 | Spans that complete faster than the optional `excludeFastQueryThresholdMs` flag will be not be 185 | reported. 186 | `excludeFastQueryThresholdMs` defaults to `0` which means disabled, can be enabled in two ways: 187 | 188 | 1. Passing system property, E.g. `-Dio.opentracing.contrib.jdbc.excludeFastQueryThresholdMs=100` 189 | 2. Modify value by code, 190 | E.g. `io.opentracing.contrib.jdbc.JdbcTracing.setExcludeFastQueryThresholdMs(100)` 191 | 192 | ## Troubleshooting 193 | 194 | In case of _Unable to find a driver_ error the database driver should be registered before 195 | configuring the datasource. E.g. `Class.forName("com.mysql.jdbc.Driver");` 196 | 197 | ## License 198 | 199 | [Apache 2.0 License](./LICENSE). 200 | 201 | [ci-img]: https://travis-ci.org/opentracing-contrib/java-jdbc.svg?branch=master 202 | 203 | [ci]: https://travis-ci.org/opentracing-contrib/java-jdbc 204 | 205 | [cov-img]: https://coveralls.io/repos/github/opentracing-contrib/java-jdbc/badge.svg?branch=master 206 | 207 | [cov]: https://coveralls.io/github/opentracing-contrib/java-jdbc?branch=master 208 | 209 | [maven-img]: https://img.shields.io/maven-central/v/io.opentracing.contrib/opentracing-jdbc.svg 210 | 211 | [maven]: http://search.maven.org/#search%7Cga%7C1%7Cio.opentracing.contrib%20opentracing-jdbc 212 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # OpenTracing Release Process 2 | 3 | This repo uses semantic versions. Please keep this in mind when choosing version numbers. 4 | 5 | For the up-to-date release process, please refer the 6 | [release process from the OpenTracing Java API](https://github.com/opentracing/opentracing-java/blob/master/RELEASE.md) 7 | . -------------------------------------------------------------------------------- /header.txt: -------------------------------------------------------------------------------- 1 | Copyright ${project.inceptionYear} The OpenTracing Authors 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 4 | in compliance with the License. You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License 9 | is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 10 | or implied. See the License for the specific language governing permissions and limitations under 11 | the License. 12 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ]; then 38 | 39 | if [ -f /etc/mavenrc ]; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ]; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false 51 | darwin=false 52 | mingw=false 53 | case "$(uname)" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true ;; 56 | Darwin*) 57 | darwin=true 58 | # 59 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 60 | # for the new JDKs provided by Oracle. 61 | # 62 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ]; then 63 | # 64 | # Apple JDKs 65 | # 66 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 67 | fi 68 | 69 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ]; then 70 | # 71 | # Apple JDKs 72 | # 73 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 74 | fi 75 | 76 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ]; then 77 | # 78 | # Oracle JDKs 79 | # 80 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 81 | fi 82 | 83 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 84 | # 85 | # Apple JDKs 86 | # 87 | export JAVA_HOME=$(/usr/libexec/java_home) 88 | fi 89 | ;; 90 | esac 91 | 92 | if [ -z "$JAVA_HOME" ]; then 93 | if [ -r /etc/gentoo-release ]; then 94 | JAVA_HOME=$(java-config --jre-home) 95 | fi 96 | fi 97 | 98 | if [ -z "$M2_HOME" ]; then 99 | ## resolve links - $0 may be a link to maven's home 100 | PRG="$0" 101 | 102 | # need this for relative symlinks 103 | while [ -h "$PRG" ]; do 104 | ls=$(ls -ld "$PRG") 105 | link=$(expr "$ls" : '.*-> \(.*\)$') 106 | if expr "$link" : '/.*' >/dev/null; then 107 | PRG="$link" 108 | else 109 | PRG="$(dirname "$PRG")/$link" 110 | fi 111 | done 112 | 113 | saveddir=$(pwd) 114 | 115 | M2_HOME=$(dirname "$PRG")/.. 116 | 117 | # make it fully qualified 118 | M2_HOME=$(cd "$M2_HOME" && pwd) 119 | 120 | cd "$saveddir" 121 | # echo Using m2 at $M2_HOME 122 | fi 123 | 124 | # For Cygwin, ensure paths are in UNIX format before anything is touched 125 | if $cygwin; then 126 | [ -n "$M2_HOME" ] && 127 | M2_HOME=$(cygpath --unix "$M2_HOME") 128 | [ -n "$JAVA_HOME" ] && 129 | JAVA_HOME=$(cygpath --unix "$JAVA_HOME") 130 | [ -n "$CLASSPATH" ] && 131 | CLASSPATH=$(cygpath --path --unix "$CLASSPATH") 132 | fi 133 | 134 | # For Migwn, ensure paths are in UNIX format before anything is touched 135 | if $mingw; then 136 | [ -n "$M2_HOME" ] && 137 | M2_HOME="$( ( 138 | cd "$M2_HOME" 139 | pwd 140 | ))" 141 | [ -n "$JAVA_HOME" ] && 142 | JAVA_HOME="$( ( 143 | cd "$JAVA_HOME" 144 | pwd 145 | ))" 146 | # TODO classpath? 147 | fi 148 | 149 | if [ -z "$JAVA_HOME" ]; then 150 | javaExecutable="$(which javac)" 151 | if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then 152 | # readlink(1) is not available as standard on Solaris 10. 153 | readLink=$(which readlink) 154 | if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then 155 | if $darwin; then 156 | javaHome="$(dirname \"$javaExecutable\")" 157 | javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac" 158 | else 159 | javaExecutable="$(readlink -f \"$javaExecutable\")" 160 | fi 161 | javaHome="$(dirname \"$javaExecutable\")" 162 | javaHome=$(expr "$javaHome" : '\(.*\)/bin') 163 | JAVA_HOME="$javaHome" 164 | export JAVA_HOME 165 | fi 166 | fi 167 | fi 168 | 169 | if [ -z "$JAVACMD" ]; then 170 | if [ -n "$JAVA_HOME" ]; then 171 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 172 | # IBM's JDK on AIX uses strange locations for the executables 173 | JAVACMD="$JAVA_HOME/jre/sh/java" 174 | else 175 | JAVACMD="$JAVA_HOME/bin/java" 176 | fi 177 | else 178 | JAVACMD="$(which java)" 179 | fi 180 | fi 181 | 182 | if [ ! -x "$JAVACMD" ]; then 183 | echo "Error: JAVA_HOME is not defined correctly." >&2 184 | echo " We cannot execute $JAVACMD" >&2 185 | exit 1 186 | fi 187 | 188 | if [ -z "$JAVA_HOME" ]; then 189 | echo "Warning: JAVA_HOME environment variable is not set." 190 | fi 191 | 192 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 193 | 194 | # traverses directory structure from process work directory to filesystem root 195 | # first directory with .mvn subdirectory is considered project base directory 196 | find_maven_basedir() { 197 | local basedir=$(pwd) 198 | local wdir=$(pwd) 199 | while [ "$wdir" != '/' ]; do 200 | if [ -d "$wdir"/.mvn ]; then 201 | basedir=$wdir 202 | break 203 | fi 204 | wdir=$( 205 | cd "$wdir/.." 206 | pwd 207 | ) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' <"$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # For Cygwin, switch paths to Windows format before running java 223 | if $cygwin; then 224 | [ -n "$M2_HOME" ] && 225 | M2_HOME=$(cygpath --path --windows "$M2_HOME") 226 | [ -n "$JAVA_HOME" ] && 227 | JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") 228 | [ -n "$CLASSPATH" ] && 229 | CLASSPATH=$(cygpath --path --windows "$CLASSPATH") 230 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 231 | MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") 232 | fi 233 | 234 | # Provide a "standardized" way to retrieve the CLI args that will 235 | # work with both Windows and non-Windows executions. 236 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 237 | export MAVEN_CMD_LINE_ARGS 238 | 239 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 240 | 241 | # avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@ 242 | exec "$JAVACMD" \ 243 | $MAVEN_OPTS \ 244 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 245 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 246 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 247 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | # avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in %* 125 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 126 | if ERRORLEVEL 1 goto error 127 | goto end 128 | 129 | :error 130 | set ERROR_CODE=1 131 | 132 | :end 133 | @endlocal & set ERROR_CODE=%ERROR_CODE% 134 | 135 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 136 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 137 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 138 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 139 | :skipRcPost 140 | 141 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 142 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 143 | 144 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 145 | 146 | exit /B %ERROR_CODE% 147 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | io.opentracing.contrib 20 | opentracing-jdbc 21 | 0.2.16-SNAPSHOT 22 | 23 | ${project.groupId}:${project.artifactId} 24 | OpenTracing Instrumentation for JDBC API 25 | https://github.com/opentracing-contrib/java-jdbc 26 | 2017-2021 27 | 28 | 29 | http://github.com/opentracing-contrib/java-jdbc 30 | scm:git:https://github.com/opentracing-contrib/java-jdbc.git 31 | scm:git:https://github.com/opentracing-contrib/java-jdbc.git 32 | 33 | HEAD 34 | 35 | 36 | 37 | 38 | The Apache Software License, Version 2.0 39 | http://www.apache.org/licenses/LICENSE-2.0.txt 40 | repo 41 | 42 | 43 | 44 | 45 | 46 | malafeev 47 | Sergei Malafeev 48 | sergeymalafeev@gmail.com 49 | 50 | 51 | 52 | 53 | GitHub 54 | https://github.com/opentracing-contrib/java-jdbc/issues 55 | 56 | 57 | 58 | 1.8 59 | 1.8 60 | UTF-8 61 | UTF-8 62 | 63 | 0.33.0 64 | 4.3.0 65 | 0.8.5 66 | 67 | 68 | 69 | 70 | io.opentracing 71 | opentracing-util 72 | ${opentracing.version} 73 | 74 | 75 | 76 | io.opentracing 77 | opentracing-util 78 | ${opentracing.version} 79 | test-jar 80 | test 81 | 82 | 83 | 84 | io.opentracing.contrib 85 | common 86 | 0.1.4 87 | 88 | 89 | 90 | io.opentracing 91 | opentracing-mock 92 | ${opentracing.version} 93 | test 94 | 95 | 96 | 97 | com.h2database 98 | h2 99 | 1.4.200 100 | test 101 | 102 | 103 | 104 | org.hibernate 105 | hibernate-core 106 | 5.4.10.Final 107 | test 108 | 109 | 110 | 111 | org.springframework 112 | spring-jdbc 113 | 5.2.2.RELEASE 114 | test 115 | 116 | 117 | 118 | org.apache.commons 119 | commons-dbcp2 120 | 2.7.0 121 | test 122 | 123 | 124 | 125 | junit 126 | junit 127 | 4.13.2 128 | test 129 | 130 | 131 | 132 | org.assertj 133 | assertj-core 134 | 3.14.0 135 | test 136 | 137 | 138 | org.junit.jupiter 139 | junit-jupiter 140 | 5.7.1 141 | test 142 | 143 | 144 | org.junit.platform 145 | junit-platform-launcher 146 | 1.7.1 147 | test 148 | 149 | 150 | org.junit.vintage 151 | junit-vintage-engine 152 | 5.7.1 153 | test 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-release-plugin 163 | 2.5.3 164 | 165 | false 166 | release 167 | true 168 | @{project.version} 169 | 170 | 171 | 172 | io.zipkin.centralsync-maven-plugin 173 | centralsync-maven-plugin 174 | 0.1.1 175 | 176 | opentracing 177 | maven 178 | opentracing-jdbc 179 | 180 | 181 | 182 | org.apache.maven.plugins 183 | maven-surefire-plugin 184 | 2.22.2 185 | 186 | 187 | com.mycila 188 | license-maven-plugin 189 | 3.0 190 | 191 | 192 | SLASHSTAR_STYLE 193 | 194 |
header.txt
195 | true 196 | 197 | LICENSE 198 | mvnw 199 | mvnw.cmd 200 | .mvn/wrapper/maven-wrapper.properties 201 | .coveralls.yml 202 | 203 |
204 | 205 | 206 | 207 | check 208 | 209 | compile 210 | 211 | 212 |
213 | 214 | org.eluder.coveralls 215 | coveralls-maven-plugin 216 | ${coveralls-maven-plugin.version} 217 | 218 | 219 | org.jacoco 220 | jacoco-maven-plugin 221 | ${jacoco-maven-plugin.version} 222 | 223 | 224 | prepare-agent 225 | 226 | prepare-agent 227 | 228 | 229 | 230 | 231 |
232 |
233 | 234 | 235 | 236 | bintray 237 | https://api.bintray.com/maven/opentracing/maven/opentracing-jdbc/;publish=1 238 | 239 | 240 | jfrog-snapshots 241 | http://oss.jfrog.org/artifactory/oss-snapshot-local 242 | 243 | 244 | 245 | 246 | 247 | release 248 | 249 | 250 | 251 | 252 | org.apache.maven.plugins 253 | maven-source-plugin 254 | 3.2.0 255 | 256 | 257 | attach-sources 258 | 259 | jar 260 | 261 | 262 | 263 | 264 | 265 | 266 | org.apache.maven.plugins 267 | maven-javadoc-plugin 268 | 3.1.1 269 | 270 | false 271 | 272 | 273 | 274 | attach-javadocs 275 | 276 | jar 277 | 278 | package 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 |
288 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/ConnectionInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | public class ConnectionInfo { 17 | 18 | public static ConnectionInfo UNKNOWN_CONNECTION_INFO = new Builder("unknown_peer") 19 | .dbType("unknown_type").dbInstance("unknown_instance").build(); 20 | 21 | private final String dbType; 22 | private final String dbUser; 23 | private final String dbInstance; 24 | private final String dbPeer; 25 | private final String dbPeerService; 26 | 27 | private ConnectionInfo(String dbType, String dbUser, String dbInstance, String dbHost, 28 | Integer dbPort) { 29 | this.dbType = dbType; 30 | this.dbUser = dbUser; 31 | this.dbInstance = dbInstance; 32 | if (dbHost != null && dbPort != null) { 33 | this.dbPeer = dbHost + ":" + dbPort; 34 | } else { 35 | this.dbPeer = ""; 36 | } 37 | 38 | this.dbPeerService = makePeerService(); 39 | } 40 | 41 | private ConnectionInfo(String dbType, String dbUser, String dbInstance, String dbPeer) { 42 | this.dbType = dbType; 43 | this.dbUser = dbUser; 44 | this.dbInstance = dbInstance; 45 | this.dbPeer = dbPeer; 46 | 47 | this.dbPeerService = makePeerService(); 48 | } 49 | 50 | /** 51 | * Make a unique serviceName that could be used in dependency diagram. 52 | */ 53 | private String makePeerService() { 54 | if (null != dbInstance && !dbInstance.isEmpty()) { 55 | return dbInstance + "[" + dbType + "(" + dbPeer + ")]"; 56 | } else { 57 | return dbType + "(" + dbPeer + ")"; 58 | } 59 | } 60 | 61 | public String getDbType() { 62 | return dbType; 63 | } 64 | 65 | public String getDbUser() { 66 | return dbUser; 67 | } 68 | 69 | public String getDbInstance() { 70 | return dbInstance; 71 | } 72 | 73 | public String getDbPeer() { 74 | return dbPeer; 75 | } 76 | 77 | public String getPeerService() { 78 | return dbPeerService; 79 | } 80 | 81 | public static class Builder { 82 | private String dbType; 83 | private String dbUser; 84 | private String dbInstance; 85 | private String dbHost; 86 | private Integer dbPort; 87 | private String dbPeer; 88 | 89 | public Builder(String dbPeer) { 90 | this.dbPeer = dbPeer; 91 | } 92 | 93 | public Builder(String dbHost, Integer dbPort) { 94 | this.dbHost = dbHost; 95 | this.dbPort = dbPort; 96 | } 97 | 98 | public Builder dbType(String dbType) { 99 | this.dbType = dbType; 100 | return this; 101 | } 102 | 103 | public Builder dbUser(String dbUser) { 104 | this.dbUser = dbUser; 105 | return this; 106 | } 107 | 108 | public Builder dbInstance(String dbInstance) { 109 | this.dbInstance = dbInstance; 110 | return this; 111 | } 112 | 113 | public ConnectionInfo build() { 114 | if (this.dbPeer != null && !dbPeer.isEmpty()) { 115 | return new ConnectionInfo(this.dbType, this.dbUser, this.dbInstance, this.dbPeer); 116 | } 117 | return new ConnectionInfo(this.dbType, this.dbUser, this.dbInstance, this.dbHost, 118 | this.dbPort); 119 | } 120 | 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/JdbcTracing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | public class JdbcTracing { 17 | private static boolean traceEnabled = true; 18 | 19 | /** 20 | * Sets the {@code traceEnabled} property to enable or disable traces. 21 | * 22 | * @param traceEnabled The {@code traceEnabled} value. 23 | */ 24 | public static void setTraceEnabled(boolean traceEnabled) { 25 | JdbcTracing.traceEnabled = traceEnabled; 26 | } 27 | 28 | public static boolean isTraceEnabled() { 29 | return JdbcTracing.traceEnabled; 30 | } 31 | 32 | /** 33 | * can be modified by application code 34 | */ 35 | private static int slowQueryThresholdMs = Integer 36 | .getInteger("io.opentracing.contrib.jdbc.slowQueryThresholdMs", 0); 37 | 38 | public static int getSlowQueryThresholdMs() { 39 | return slowQueryThresholdMs; 40 | } 41 | 42 | public static void setSlowQueryThresholdMs(final int slowQueryThresholdMs) { 43 | JdbcTracing.slowQueryThresholdMs = slowQueryThresholdMs; 44 | } 45 | 46 | private static int excludeFastQueryThresholdMs = Integer 47 | .getInteger("io.opentracing.contrib.jdbc.excludeFastQueryThresholdMs", 0); 48 | 49 | public static int getExcludeFastQueryThresholdMs() { 50 | return excludeFastQueryThresholdMs; 51 | } 52 | 53 | public static void setExcludeFastQueryThresholdMs(final int excludeFastQueryThresholdMs) { 54 | JdbcTracing.excludeFastQueryThresholdMs = excludeFastQueryThresholdMs; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/JdbcTracingUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import io.opentracing.Scope; 17 | import io.opentracing.Span; 18 | import io.opentracing.Tracer; 19 | import io.opentracing.noop.NoopSpan; 20 | import io.opentracing.tag.BooleanTag; 21 | import io.opentracing.tag.IntTag; 22 | import io.opentracing.tag.StringTag; 23 | import io.opentracing.tag.Tags; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | import java.util.Set; 27 | import java.util.concurrent.TimeUnit; 28 | 29 | class JdbcTracingUtils { 30 | 31 | static final String COMPONENT_NAME = "java-jdbc"; 32 | 33 | /** 34 | * Opentracing standard tag https://github.com/opentracing/specification/blob/master/semantic_conventions.md 35 | */ 36 | static final StringTag PEER_ADDRESS = new StringTag("peer.address"); 37 | 38 | static final BooleanTag SLOW = new BooleanTag("slow"); 39 | static final IntTag SAMPLING_PRIORITY = new IntTag("sampling.priority"); 40 | 41 | static Span buildSpan(String operationName, 42 | String sql, 43 | ConnectionInfo connectionInfo, 44 | boolean withActiveSpanOnly, 45 | Set ignoreStatements, 46 | Tracer tracer) { 47 | if (!JdbcTracing.isTraceEnabled() || (withActiveSpanOnly && tracer.activeSpan() == null)) { 48 | return NoopSpan.INSTANCE; 49 | } else if (ignoreStatements != null && ignoreStatements.contains(sql)) { 50 | return NoopSpan.INSTANCE; 51 | } 52 | 53 | Tracer.SpanBuilder spanBuilder = tracer.buildSpan(operationName) 54 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT); 55 | 56 | Span span = spanBuilder.start(); 57 | decorate(span, sql, connectionInfo); 58 | 59 | return span; 60 | } 61 | 62 | static void execute(String operationName, 63 | CheckedRunnable runnable, 64 | String sql, 65 | ConnectionInfo connectionInfo, 66 | boolean withActiveSpanOnly, 67 | Set ignoreStatements, 68 | Tracer tracer) throws E { 69 | if (!JdbcTracing.isTraceEnabled() || (withActiveSpanOnly && tracer.activeSpan() == null)) { 70 | runnable.run(); 71 | return; 72 | } 73 | 74 | final Span span = buildSpan(operationName, sql, connectionInfo, withActiveSpanOnly, 75 | ignoreStatements, tracer); 76 | long startTime = (JdbcTracing.getSlowQueryThresholdMs() > 0 77 | || JdbcTracing.getExcludeFastQueryThresholdMs() > 0) ? System.nanoTime() : 0; 78 | try (Scope ignored = tracer.activateSpan(span)) { 79 | runnable.run(); 80 | } catch (Exception e) { 81 | JdbcTracingUtils.onError(e, span); 82 | throw e; 83 | } finally { 84 | JdbcTracingUtils.queryThresholdChecks(span, startTime); 85 | span.finish(); 86 | } 87 | } 88 | 89 | static T call(String operationName, 90 | CheckedCallable callable, 91 | String sql, 92 | ConnectionInfo connectionInfo, 93 | boolean withActiveSpanOnly, 94 | Set ignoreStatements, 95 | Tracer tracer) throws E { 96 | if (!JdbcTracing.isTraceEnabled() || (withActiveSpanOnly && tracer.activeSpan() == null)) { 97 | return callable.call(); 98 | } 99 | 100 | final Span span = buildSpan(operationName, sql, connectionInfo, withActiveSpanOnly, 101 | ignoreStatements, tracer); 102 | long startTime = JdbcTracing.getSlowQueryThresholdMs() > 0 ? System.nanoTime() : 0; 103 | try (Scope ignored = tracer.activateSpan(span)) { 104 | return callable.call(); 105 | } catch (Exception e) { 106 | JdbcTracingUtils.onError(e, span); 107 | throw e; 108 | } finally { 109 | JdbcTracingUtils.queryThresholdChecks(span, startTime); 110 | span.finish(); 111 | } 112 | } 113 | 114 | private static boolean isNotEmpty(CharSequence s) { 115 | return s != null && !"".contentEquals(s); 116 | } 117 | 118 | /** 119 | * Add tags to span. Skip empty tags to avoid reported NPE in tracers. 120 | */ 121 | private static void decorate(Span span, String sql, ConnectionInfo connectionInfo) { 122 | Tags.COMPONENT.set(span, COMPONENT_NAME); 123 | 124 | if (isNotEmpty(sql)) { 125 | Tags.DB_STATEMENT.set(span, sql); 126 | } 127 | if (isNotEmpty(connectionInfo.getDbType())) { 128 | Tags.DB_TYPE.set(span, connectionInfo.getDbType()); 129 | } 130 | if (isNotEmpty(connectionInfo.getDbPeer())) { 131 | PEER_ADDRESS.set(span, connectionInfo.getDbPeer()); 132 | } 133 | if (isNotEmpty(connectionInfo.getDbInstance())) { 134 | Tags.DB_INSTANCE.set(span, connectionInfo.getDbInstance()); 135 | } 136 | if (isNotEmpty(connectionInfo.getDbUser())) { 137 | Tags.DB_USER.set(span, connectionInfo.getDbUser()); 138 | } 139 | if (isNotEmpty(connectionInfo.getPeerService())) { 140 | Tags.PEER_SERVICE.set(span, connectionInfo.getPeerService()); 141 | } 142 | } 143 | 144 | static void onError(Throwable throwable, Span span) { 145 | Tags.ERROR.set(span, Boolean.TRUE); 146 | 147 | if (throwable != null) { 148 | span.log(errorLogs(throwable)); 149 | } 150 | } 151 | 152 | private static Map errorLogs(Throwable throwable) { 153 | Map errorLogs = new HashMap<>(3); 154 | errorLogs.put("event", Tags.ERROR.getKey()); 155 | errorLogs.put("error.object", throwable); 156 | return errorLogs; 157 | } 158 | 159 | private static void queryThresholdChecks(Span span, long startTime) { 160 | long completionTime = System.nanoTime() - startTime; 161 | if (JdbcTracing.getExcludeFastQueryThresholdMs() > 0 && completionTime < TimeUnit.MILLISECONDS 162 | .toNanos(JdbcTracing.getExcludeFastQueryThresholdMs())) { 163 | SAMPLING_PRIORITY.set(span, 0); 164 | } 165 | if (JdbcTracing.getSlowQueryThresholdMs() > 0 && completionTime > TimeUnit.MILLISECONDS 166 | .toNanos(JdbcTracing.getSlowQueryThresholdMs())) { 167 | SLOW.set(span, true); 168 | } 169 | } 170 | 171 | @FunctionalInterface 172 | interface CheckedRunnable { 173 | 174 | void run() throws E; 175 | 176 | } 177 | 178 | @FunctionalInterface 179 | interface CheckedCallable { 180 | 181 | T call() throws E; 182 | 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/TracingConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import io.opentracing.Tracer; 17 | import io.opentracing.contrib.common.WrapperProxy; 18 | import java.sql.Array; 19 | import java.sql.Blob; 20 | import java.sql.CallableStatement; 21 | import java.sql.Clob; 22 | import java.sql.Connection; 23 | import java.sql.DatabaseMetaData; 24 | import java.sql.NClob; 25 | import java.sql.PreparedStatement; 26 | import java.sql.SQLClientInfoException; 27 | import java.sql.SQLException; 28 | import java.sql.SQLWarning; 29 | import java.sql.SQLXML; 30 | import java.sql.Savepoint; 31 | import java.sql.Statement; 32 | import java.sql.Struct; 33 | import java.util.Map; 34 | import java.util.Properties; 35 | import java.util.Set; 36 | import java.util.concurrent.Executor; 37 | 38 | public class TracingConnection implements Connection { 39 | private final Connection connection; 40 | private final ConnectionInfo connectionInfo; 41 | private final boolean withActiveSpanOnly; 42 | private final Set ignoreStatements; 43 | private final Tracer tracer; 44 | 45 | public TracingConnection(Connection connection, ConnectionInfo connectionInfo, 46 | boolean withActiveSpanOnly, Set ignoreStatements, Tracer tracer) { 47 | this.connection = connection; 48 | this.connectionInfo = connectionInfo; 49 | this.withActiveSpanOnly = withActiveSpanOnly; 50 | this.ignoreStatements = ignoreStatements; 51 | this.tracer = tracer; 52 | } 53 | 54 | @Override 55 | public Statement createStatement() throws SQLException { 56 | final Statement statement = connection.createStatement(); 57 | return WrapperProxy 58 | .wrap(statement, new TracingStatement(statement, connectionInfo, withActiveSpanOnly, 59 | ignoreStatements, tracer)); 60 | } 61 | 62 | @Override 63 | public Statement createStatement(int resultSetType, int resultSetConcurrency) 64 | throws SQLException { 65 | final Statement statement = connection.createStatement(resultSetType, resultSetConcurrency); 66 | return WrapperProxy.wrap(statement, new TracingStatement(statement, 67 | connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 68 | } 69 | 70 | @Override 71 | public Statement createStatement(int resultSetType, int resultSetConcurrency, 72 | int resultSetHoldability) throws SQLException { 73 | final Statement statement = connection 74 | .createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); 75 | return WrapperProxy.wrap(statement, new TracingStatement(statement, 76 | connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 77 | } 78 | 79 | @Override 80 | public PreparedStatement prepareStatement(String sql) throws SQLException { 81 | final PreparedStatement statement = connection.prepareStatement(sql); 82 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, sql, connectionInfo, 83 | withActiveSpanOnly, ignoreStatements, tracer)); 84 | } 85 | 86 | @Override 87 | public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) 88 | throws SQLException { 89 | final PreparedStatement statement = connection 90 | .prepareStatement(sql, resultSetType, resultSetConcurrency); 91 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, sql, connectionInfo, 92 | withActiveSpanOnly, ignoreStatements, tracer)); 93 | } 94 | 95 | @Override 96 | public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, 97 | int resultSetHoldability) throws SQLException { 98 | final PreparedStatement statement = connection 99 | .prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 100 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, 101 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 102 | } 103 | 104 | @Override 105 | public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { 106 | final PreparedStatement statement = connection.prepareStatement(sql, autoGeneratedKeys); 107 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, sql, 108 | connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 109 | } 110 | 111 | @Override 112 | public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { 113 | final PreparedStatement statement = connection.prepareStatement(sql, columnIndexes); 114 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, sql, 115 | connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 116 | } 117 | 118 | @Override 119 | public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { 120 | final PreparedStatement statement = connection.prepareStatement(sql, columnNames); 121 | return WrapperProxy.wrap(statement, new TracingPreparedStatement(statement, sql, connectionInfo, 122 | withActiveSpanOnly, ignoreStatements, tracer)); 123 | } 124 | 125 | @Override 126 | public CallableStatement prepareCall(String sql) throws SQLException { 127 | final CallableStatement statement = connection.prepareCall(sql); 128 | return WrapperProxy.wrap(statement, 129 | new TracingCallableStatement(statement, sql, connectionInfo, 130 | withActiveSpanOnly, ignoreStatements, tracer)); 131 | } 132 | 133 | @Override 134 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) 135 | throws SQLException { 136 | final CallableStatement statement = connection 137 | .prepareCall(sql, resultSetType, resultSetConcurrency); 138 | return WrapperProxy.wrap(statement, new TracingCallableStatement(statement, sql, connectionInfo, 139 | withActiveSpanOnly, ignoreStatements, tracer)); 140 | } 141 | 142 | @Override 143 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, 144 | int resultSetHoldability) throws SQLException { 145 | final CallableStatement statement = connection 146 | .prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 147 | return WrapperProxy.wrap(statement, new TracingCallableStatement(statement, sql, 148 | connectionInfo, withActiveSpanOnly, ignoreStatements, tracer)); 149 | } 150 | 151 | @Override 152 | public void commit() throws SQLException { 153 | JdbcTracingUtils.execute("Commit", connection::commit, null, 154 | connectionInfo, withActiveSpanOnly, null, tracer); 155 | } 156 | 157 | @Override 158 | public void rollback() throws SQLException { 159 | JdbcTracingUtils.execute("Rollback", connection::rollback, null, 160 | connectionInfo, withActiveSpanOnly, null, tracer); 161 | } 162 | 163 | @Override 164 | public void close() throws SQLException { 165 | JdbcTracingUtils.execute("Close", connection::close, null, 166 | connectionInfo, withActiveSpanOnly, null, tracer); 167 | } 168 | 169 | @Override 170 | public String nativeSQL(String sql) throws SQLException { 171 | return connection.nativeSQL(sql); 172 | } 173 | 174 | @Override 175 | public void setAutoCommit(boolean autoCommit) throws SQLException { 176 | connection.setAutoCommit(autoCommit); 177 | } 178 | 179 | @Override 180 | public boolean getAutoCommit() throws SQLException { 181 | return connection.getAutoCommit(); 182 | } 183 | 184 | @Override 185 | public boolean isClosed() throws SQLException { 186 | return connection.isClosed(); 187 | } 188 | 189 | @Override 190 | public DatabaseMetaData getMetaData() throws SQLException { 191 | return connection.getMetaData(); 192 | } 193 | 194 | @Override 195 | public void setReadOnly(boolean readOnly) throws SQLException { 196 | connection.setReadOnly(readOnly); 197 | } 198 | 199 | @Override 200 | public boolean isReadOnly() throws SQLException { 201 | return connection.isReadOnly(); 202 | } 203 | 204 | @Override 205 | public void setCatalog(String catalog) throws SQLException { 206 | connection.setCatalog(catalog); 207 | } 208 | 209 | @Override 210 | public String getCatalog() throws SQLException { 211 | return connection.getCatalog(); 212 | } 213 | 214 | @Override 215 | public void setTransactionIsolation(int level) throws SQLException { 216 | connection.setTransactionIsolation(level); 217 | } 218 | 219 | @Override 220 | public int getTransactionIsolation() throws SQLException { 221 | return connection.getTransactionIsolation(); 222 | } 223 | 224 | @Override 225 | public SQLWarning getWarnings() throws SQLException { 226 | return connection.getWarnings(); 227 | } 228 | 229 | @Override 230 | public void clearWarnings() throws SQLException { 231 | connection.clearWarnings(); 232 | } 233 | 234 | @Override 235 | public Map> getTypeMap() throws SQLException { 236 | return connection.getTypeMap(); 237 | } 238 | 239 | @Override 240 | public void setTypeMap(Map> map) throws SQLException { 241 | connection.setTypeMap(map); 242 | } 243 | 244 | @Override 245 | public void setHoldability(int holdability) throws SQLException { 246 | connection.setHoldability(holdability); 247 | } 248 | 249 | @Override 250 | public int getHoldability() throws SQLException { 251 | return connection.getHoldability(); 252 | } 253 | 254 | @Override 255 | public Savepoint setSavepoint() throws SQLException { 256 | return connection.setSavepoint(); 257 | } 258 | 259 | @Override 260 | public Savepoint setSavepoint(String name) throws SQLException { 261 | return connection.setSavepoint(name); 262 | } 263 | 264 | @Override 265 | public void rollback(Savepoint savepoint) throws SQLException { 266 | connection.rollback(savepoint); 267 | } 268 | 269 | @Override 270 | public void releaseSavepoint(Savepoint savepoint) throws SQLException { 271 | connection.releaseSavepoint(savepoint); 272 | } 273 | 274 | @Override 275 | public Clob createClob() throws SQLException { 276 | return connection.createClob(); 277 | } 278 | 279 | @Override 280 | public Blob createBlob() throws SQLException { 281 | return connection.createBlob(); 282 | } 283 | 284 | @Override 285 | public NClob createNClob() throws SQLException { 286 | return connection.createNClob(); 287 | } 288 | 289 | @Override 290 | public SQLXML createSQLXML() throws SQLException { 291 | return connection.createSQLXML(); 292 | } 293 | 294 | @Override 295 | public boolean isValid(int timeout) throws SQLException { 296 | return connection.isValid(timeout); 297 | } 298 | 299 | @Override 300 | public void setClientInfo(String name, String value) throws SQLClientInfoException { 301 | connection.setClientInfo(name, value); 302 | } 303 | 304 | @Override 305 | public void setClientInfo(Properties properties) throws SQLClientInfoException { 306 | connection.setClientInfo(properties); 307 | } 308 | 309 | @Override 310 | public String getClientInfo(String name) throws SQLException { 311 | return connection.getClientInfo(name); 312 | } 313 | 314 | @Override 315 | public Properties getClientInfo() throws SQLException { 316 | return connection.getClientInfo(); 317 | } 318 | 319 | @Override 320 | public Array createArrayOf(String typeName, Object[] elements) throws SQLException { 321 | return connection.createArrayOf(typeName, elements); 322 | } 323 | 324 | @Override 325 | public Struct createStruct(String typeName, Object[] attributes) throws SQLException { 326 | return connection.createStruct(typeName, attributes); 327 | } 328 | 329 | @Override 330 | public void setSchema(String schema) throws SQLException { 331 | connection.setSchema(schema); 332 | } 333 | 334 | @Override 335 | public String getSchema() throws SQLException { 336 | return connection.getSchema(); 337 | } 338 | 339 | @Override 340 | public void abort(Executor executor) throws SQLException { 341 | connection.abort(executor); 342 | } 343 | 344 | @Override 345 | public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { 346 | connection.setNetworkTimeout(executor, milliseconds); 347 | } 348 | 349 | @Override 350 | public int getNetworkTimeout() throws SQLException { 351 | return connection.getNetworkTimeout(); 352 | } 353 | 354 | @Override 355 | public T unwrap(Class iface) throws SQLException { 356 | return connection.unwrap(iface); 357 | } 358 | 359 | @Override 360 | public boolean isWrapperFor(Class iface) throws SQLException { 361 | return connection.isWrapperFor(iface); 362 | } 363 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/TracingDataSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import io.opentracing.Tracer; 18 | import io.opentracing.contrib.common.WrapperProxy; 19 | import io.opentracing.contrib.jdbc.parser.URLParser; 20 | import java.io.PrintWriter; 21 | import java.lang.reflect.Method; 22 | import java.sql.Connection; 23 | import java.sql.SQLException; 24 | import java.sql.SQLFeatureNotSupportedException; 25 | import java.util.Collections; 26 | import java.util.Set; 27 | import java.util.logging.Logger; 28 | import javax.sql.DataSource; 29 | 30 | public class TracingDataSource implements DataSource, AutoCloseable { 31 | private static final boolean DEFAULT_WITH_ACTIVE_SPAN_ONLY = false; 32 | private static final Set DEFAULT_IGNORED_STATEMENTS = Collections.emptySet(); 33 | 34 | private final Tracer tracer; 35 | private final DataSource underlying; 36 | private final ConnectionInfo connectionInfo; 37 | private final boolean withActiveSpanOnly; 38 | private final Set ignoreStatements; 39 | 40 | public TracingDataSource(final Tracer tracer, 41 | final DataSource underlying) { 42 | this(tracer, underlying, null, DEFAULT_WITH_ACTIVE_SPAN_ONLY, 43 | DEFAULT_IGNORED_STATEMENTS); 44 | } 45 | 46 | public TracingDataSource(final Tracer tracer, 47 | final DataSource underlying, 48 | final ConnectionInfo connectionInfo, 49 | final boolean withActiveSpanOnly, 50 | final Set ignoreStatements) { 51 | this.tracer = tracer; 52 | this.underlying = underlying; 53 | ConnectionInfo info = connectionInfo; 54 | if (info == null) { 55 | try { 56 | Method method; 57 | try { 58 | method = underlying.getClass().getMethod("getJdbcUrl"); 59 | } catch (NoSuchMethodException e) { 60 | method = underlying.getClass().getMethod("getUrl"); 61 | } 62 | info = URLParser.parse((String) method.invoke(underlying)); 63 | } catch (Exception ignored) { 64 | info = ConnectionInfo.UNKNOWN_CONNECTION_INFO; 65 | } 66 | } 67 | this.connectionInfo = info; 68 | this.withActiveSpanOnly = withActiveSpanOnly; 69 | this.ignoreStatements = ignoreStatements; 70 | } 71 | 72 | public DataSource getUnderlying() { 73 | return underlying; 74 | } 75 | 76 | @Override 77 | public Connection getConnection() throws SQLException { 78 | final Connection connection = JdbcTracingUtils 79 | .call("AcquireConnection", underlying::getConnection, 80 | null, connectionInfo, withActiveSpanOnly, null, tracer); 81 | 82 | return WrapperProxy 83 | .wrap(connection, new TracingConnection(connection, connectionInfo, withActiveSpanOnly, 84 | ignoreStatements, tracer)); 85 | } 86 | 87 | @Override 88 | public Connection getConnection(final String username, final String password) 89 | throws SQLException { 90 | final Connection connection = JdbcTracingUtils.call("AcquireConnection", () -> 91 | underlying.getConnection(username, password), null, connectionInfo, 92 | withActiveSpanOnly, null, tracer); 93 | 94 | return WrapperProxy 95 | .wrap(connection, new TracingConnection(connection, connectionInfo, withActiveSpanOnly, 96 | ignoreStatements, tracer)); 97 | } 98 | 99 | @Override 100 | public PrintWriter getLogWriter() throws SQLException { 101 | return underlying.getLogWriter(); 102 | } 103 | 104 | @Override 105 | public void setLogWriter(final PrintWriter out) throws SQLException { 106 | underlying.setLogWriter(out); 107 | } 108 | 109 | @Override 110 | public void setLoginTimeout(final int seconds) throws SQLException { 111 | underlying.setLoginTimeout(seconds); 112 | } 113 | 114 | @Override 115 | public int getLoginTimeout() throws SQLException { 116 | return underlying.getLoginTimeout(); 117 | } 118 | 119 | @Override 120 | public Logger getParentLogger() throws SQLFeatureNotSupportedException { 121 | return underlying.getParentLogger(); 122 | } 123 | 124 | @Override 125 | public T unwrap(final Class iface) throws SQLException { 126 | return underlying.unwrap(iface); 127 | } 128 | 129 | @Override 130 | public boolean isWrapperFor(final Class iface) throws SQLException { 131 | return underlying.isWrapperFor(iface); 132 | } 133 | 134 | @Override 135 | public void close() throws Exception { 136 | if (underlying instanceof AutoCloseable) { 137 | ((AutoCloseable) underlying).close(); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/TracingDriver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import io.opentracing.Tracer; 17 | import io.opentracing.contrib.common.WrapperProxy; 18 | import io.opentracing.contrib.jdbc.parser.URLParser; 19 | import io.opentracing.util.GlobalTracer; 20 | import java.sql.Connection; 21 | import java.sql.Driver; 22 | import java.sql.DriverManager; 23 | import java.sql.DriverPropertyInfo; 24 | import java.sql.SQLException; 25 | import java.sql.SQLFeatureNotSupportedException; 26 | import java.util.ArrayList; 27 | import java.util.Collections; 28 | import java.util.Enumeration; 29 | import java.util.HashSet; 30 | import java.util.List; 31 | import java.util.Properties; 32 | import java.util.Set; 33 | import java.util.logging.Logger; 34 | import java.util.regex.Matcher; 35 | import java.util.regex.Pattern; 36 | 37 | public class TracingDriver implements Driver { 38 | 39 | private static final Driver INSTANCE = new TracingDriver(); 40 | 41 | protected static final String TRACE_WITH_ACTIVE_SPAN_ONLY = "traceWithActiveSpanOnly"; 42 | 43 | protected static final String WITH_ACTIVE_SPAN_ONLY = TRACE_WITH_ACTIVE_SPAN_ONLY + "=true"; 44 | 45 | public static final String IGNORE_FOR_TRACING_REGEX = "ignoreForTracing=\"((?:\\\\\"|[^\"])*)\"[;]*"; 46 | 47 | protected static final Pattern PATTERN_FOR_IGNORING = Pattern.compile(IGNORE_FOR_TRACING_REGEX); 48 | 49 | static { 50 | try { 51 | DriverManager.registerDriver(INSTANCE); 52 | } catch (SQLException e) { 53 | throw new IllegalStateException("Could not register TracingDriver with DriverManager", e); 54 | } 55 | } 56 | 57 | /** 58 | * @return The singleton instance of the {@code TracingDriver}. 59 | */ 60 | public static Driver load() { 61 | return INSTANCE; 62 | } 63 | 64 | /** 65 | * Ensure {@code TracingDriver} be the first driver of {@link DriverManager} to make sure 66 | * "interceptor mode" works. WARNING: Driver like Oracle JDBC may fail since it's destroyed 67 | * forever after deregistration. 68 | */ 69 | public synchronized static void ensureRegisteredAsTheFirstDriver() { 70 | try { 71 | Enumeration enumeration = DriverManager.getDrivers(); 72 | List drivers = null; 73 | for (int i = 0; enumeration.hasMoreElements(); ++i) { 74 | Driver driver = enumeration.nextElement(); 75 | if (i == 0) { 76 | if (driver == INSTANCE) { 77 | return; 78 | } 79 | drivers = new ArrayList<>(); 80 | } 81 | if (driver != INSTANCE) { 82 | drivers.add(driver); 83 | DriverManager.deregisterDriver(driver); 84 | } 85 | } 86 | for (Driver driver : drivers) { 87 | DriverManager.registerDriver(driver); 88 | } 89 | } catch (SQLException e) { 90 | throw new IllegalStateException("Could not register TracingDriver with DriverManager", e); 91 | } 92 | } 93 | 94 | /** 95 | * Sets the {@code traceEnabled} property to enable or disable traces. 96 | * 97 | * @param traceEnabled The {@code traceEnabled} value. 98 | */ 99 | public static void setTraceEnabled(boolean traceEnabled) { 100 | JdbcTracing.setTraceEnabled(traceEnabled); 101 | } 102 | 103 | public static boolean isTraceEnabled() { 104 | return JdbcTracing.isTraceEnabled(); 105 | } 106 | 107 | private static boolean interceptorMode = false; 108 | 109 | /** 110 | * Turns "interceptor mode" on or off. 111 | * 112 | * @param interceptorMode The {@code interceptorMode} value. 113 | */ 114 | public static void setInterceptorMode(final boolean interceptorMode) { 115 | TracingDriver.interceptorMode = interceptorMode; 116 | } 117 | 118 | private static boolean withActiveSpanOnly; 119 | 120 | /** 121 | * Sets the {@code withActiveSpanOnly} property for "interceptor mode". 122 | * 123 | * @param withActiveSpanOnly The {@code withActiveSpanOnly} value. 124 | */ 125 | public static void setInterceptorProperty(final boolean withActiveSpanOnly) { 126 | TracingDriver.withActiveSpanOnly = withActiveSpanOnly; 127 | } 128 | 129 | private static Set ignoreStatements; 130 | 131 | /** 132 | * Sets the {@code ignoreStatements} property for "interceptor mode". 133 | * 134 | * @param ignoreStatements The {@code ignoreStatements} value. 135 | */ 136 | public static void setInterceptorProperty(final Set ignoreStatements) { 137 | TracingDriver.ignoreStatements = ignoreStatements; 138 | } 139 | 140 | protected Tracer tracer; 141 | 142 | @Override 143 | public Connection connect(String url, Properties info) throws SQLException { 144 | // if there is no url, we have problems 145 | if (url == null) { 146 | throw new SQLException("url is required"); 147 | } 148 | 149 | final Set ignoreStatements; 150 | final boolean withActiveSpanOnly; 151 | if (interceptorMode) { 152 | withActiveSpanOnly = TracingDriver.withActiveSpanOnly; 153 | ignoreStatements = TracingDriver.ignoreStatements; 154 | } else if (acceptsURL(url)) { 155 | withActiveSpanOnly = url.contains(WITH_ACTIVE_SPAN_ONLY); 156 | ignoreStatements = extractIgnoredStatements(url); 157 | } else { 158 | return null; 159 | } 160 | 161 | url = extractRealUrl(url); 162 | 163 | // find the real driver for the URL 164 | final Driver wrappedDriver = findDriver(url); 165 | 166 | final Tracer currentTracer = getTracer(); 167 | final ConnectionInfo connectionInfo = URLParser.parse(url); 168 | final String realUrl = url; 169 | final Connection connection = JdbcTracingUtils.call("AcquireConnection", () -> 170 | wrappedDriver.connect(realUrl, info), null, connectionInfo, withActiveSpanOnly, 171 | null, currentTracer); 172 | 173 | return WrapperProxy 174 | .wrap(connection, new TracingConnection(connection, connectionInfo, withActiveSpanOnly, 175 | ignoreStatements, currentTracer)); 176 | } 177 | 178 | @Override 179 | public boolean acceptsURL(String url) throws SQLException { 180 | return url != null && ( 181 | url.startsWith(getUrlPrefix()) || 182 | (interceptorMode && url.startsWith("jdbc:")) 183 | ); 184 | } 185 | 186 | @Override 187 | public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { 188 | return findDriver(url).getPropertyInfo(url, info); 189 | } 190 | 191 | @Override 192 | public int getMajorVersion() { 193 | // There is no way to get it from wrapped driver 194 | return 1; 195 | } 196 | 197 | @Override 198 | public int getMinorVersion() { 199 | // There is no way to get it from wrapped driver 200 | return 0; 201 | } 202 | 203 | @Override 204 | public boolean jdbcCompliant() { 205 | return true; 206 | } 207 | 208 | @Override 209 | public Logger getParentLogger() throws SQLFeatureNotSupportedException { 210 | // There is no way to get it from wrapped driver 211 | return null; 212 | } 213 | 214 | public void setTracer(Tracer tracer) { 215 | this.tracer = tracer; 216 | } 217 | 218 | protected String getUrlPrefix() { 219 | return "jdbc:tracing:"; 220 | } 221 | 222 | protected Driver findDriver(String realUrl) throws SQLException { 223 | if (realUrl == null || realUrl.trim().length() == 0) { 224 | throw new IllegalArgumentException("url is required"); 225 | } 226 | 227 | for (Driver candidate : Collections.list(DriverManager.getDrivers())) { 228 | try { 229 | if (!(candidate instanceof TracingDriver) && candidate.acceptsURL(realUrl)) { 230 | return candidate; 231 | } 232 | } catch (SQLException ignored) { 233 | // intentionally ignore exception 234 | } 235 | } 236 | 237 | throw new SQLException("Unable to find a driver that accepts url: " + realUrl); 238 | } 239 | 240 | protected String extractRealUrl(String url) { 241 | String extracted = url.startsWith(getUrlPrefix()) ? url.replace(getUrlPrefix(), "jdbc:") : url; 242 | return extracted.replaceAll(TRACE_WITH_ACTIVE_SPAN_ONLY + "=(true|false)[;]*", "") 243 | .replaceAll(IGNORE_FOR_TRACING_REGEX, "") 244 | .replaceAll("\\?$", ""); 245 | } 246 | 247 | protected Set extractIgnoredStatements(String url) { 248 | 249 | final Matcher matcher = PATTERN_FOR_IGNORING.matcher(url); 250 | 251 | Set results = new HashSet<>(8); 252 | 253 | while (matcher.find()) { 254 | String rawValue = matcher.group(1); 255 | String finalValue = rawValue.replace("\\\"", "\""); 256 | results.add(finalValue); 257 | } 258 | 259 | return results; 260 | } 261 | 262 | Tracer getTracer() { 263 | if (tracer == null) { 264 | return GlobalTracer.get(); 265 | } 266 | return tracer; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/TracingPreparedStatement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import io.opentracing.Tracer; 18 | import java.io.InputStream; 19 | import java.io.Reader; 20 | import java.math.BigDecimal; 21 | import java.net.URL; 22 | import java.sql.Array; 23 | import java.sql.Blob; 24 | import java.sql.Clob; 25 | import java.sql.Date; 26 | import java.sql.NClob; 27 | import java.sql.ParameterMetaData; 28 | import java.sql.PreparedStatement; 29 | import java.sql.Ref; 30 | import java.sql.ResultSet; 31 | import java.sql.ResultSetMetaData; 32 | import java.sql.RowId; 33 | import java.sql.SQLException; 34 | import java.sql.SQLXML; 35 | import java.sql.Time; 36 | import java.sql.Timestamp; 37 | import java.util.Calendar; 38 | import java.util.Set; 39 | 40 | public class TracingPreparedStatement extends TracingStatement implements PreparedStatement { 41 | 42 | private final PreparedStatement preparedStatement; 43 | private final String query; 44 | 45 | public TracingPreparedStatement(PreparedStatement preparedStatement, String query, 46 | ConnectionInfo connectionInfo, boolean withActiveSpanOnly, Set ignoreStatements, 47 | Tracer tracer) { 48 | super(preparedStatement, query, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 49 | this.preparedStatement = preparedStatement; 50 | this.query = query; 51 | } 52 | 53 | @Override 54 | public ResultSet executeQuery() throws SQLException { 55 | return JdbcTracingUtils.call("Query", preparedStatement::executeQuery, 56 | query, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 57 | } 58 | 59 | @Override 60 | public int executeUpdate() throws SQLException { 61 | return JdbcTracingUtils.call("Update", preparedStatement::executeUpdate, 62 | query, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 63 | } 64 | 65 | @Override 66 | public boolean execute() throws SQLException { 67 | return JdbcTracingUtils.call("Execute", preparedStatement::execute, 68 | query, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 69 | } 70 | 71 | @Override 72 | public void setNull(int parameterIndex, int sqlType) throws SQLException { 73 | preparedStatement.setNull(parameterIndex, sqlType); 74 | } 75 | 76 | @Override 77 | public void setBoolean(int parameterIndex, boolean x) throws SQLException { 78 | preparedStatement.setBoolean(parameterIndex, x); 79 | } 80 | 81 | @Override 82 | public void setByte(int parameterIndex, byte x) throws SQLException { 83 | preparedStatement.setByte(parameterIndex, x); 84 | } 85 | 86 | @Override 87 | public void setShort(int parameterIndex, short x) throws SQLException { 88 | preparedStatement.setShort(parameterIndex, x); 89 | } 90 | 91 | @Override 92 | public void setInt(int parameterIndex, int x) throws SQLException { 93 | preparedStatement.setInt(parameterIndex, x); 94 | } 95 | 96 | @Override 97 | public void setLong(int parameterIndex, long x) throws SQLException { 98 | preparedStatement.setLong(parameterIndex, x); 99 | } 100 | 101 | @Override 102 | public void setFloat(int parameterIndex, float x) throws SQLException { 103 | preparedStatement.setFloat(parameterIndex, x); 104 | } 105 | 106 | @Override 107 | public void setDouble(int parameterIndex, double x) throws SQLException { 108 | preparedStatement.setDouble(parameterIndex, x); 109 | } 110 | 111 | @Override 112 | public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { 113 | preparedStatement.setBigDecimal(parameterIndex, x); 114 | } 115 | 116 | @Override 117 | public void setString(int parameterIndex, String x) throws SQLException { 118 | preparedStatement.setString(parameterIndex, x); 119 | } 120 | 121 | @Override 122 | public void setBytes(int parameterIndex, byte[] x) throws SQLException { 123 | preparedStatement.setBytes(parameterIndex, x); 124 | } 125 | 126 | @Override 127 | public void setDate(int parameterIndex, Date x) throws SQLException { 128 | preparedStatement.setDate(parameterIndex, x); 129 | } 130 | 131 | @Override 132 | public void setTime(int parameterIndex, Time x) throws SQLException { 133 | preparedStatement.setTime(parameterIndex, x); 134 | } 135 | 136 | @Override 137 | public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { 138 | preparedStatement.setTimestamp(parameterIndex, x); 139 | } 140 | 141 | @Override 142 | public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { 143 | preparedStatement.setAsciiStream(parameterIndex, x, length); 144 | } 145 | 146 | @Override 147 | @Deprecated 148 | public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { 149 | preparedStatement.setUnicodeStream(parameterIndex, x, length); 150 | } 151 | 152 | @Override 153 | public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { 154 | preparedStatement.setBinaryStream(parameterIndex, x, length); 155 | } 156 | 157 | @Override 158 | public void clearParameters() throws SQLException { 159 | preparedStatement.clearParameters(); 160 | } 161 | 162 | @Override 163 | public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { 164 | preparedStatement.setObject(parameterIndex, x, targetSqlType); 165 | } 166 | 167 | @Override 168 | public void setObject(int parameterIndex, Object x) throws SQLException { 169 | preparedStatement.setObject(parameterIndex, x); 170 | } 171 | 172 | @Override 173 | public void addBatch() throws SQLException { 174 | preparedStatement.addBatch(); 175 | } 176 | 177 | @Override 178 | public void setCharacterStream(int parameterIndex, Reader reader, int length) 179 | throws SQLException { 180 | preparedStatement.setCharacterStream(parameterIndex, reader, length); 181 | } 182 | 183 | @Override 184 | public void setRef(int parameterIndex, Ref x) throws SQLException { 185 | preparedStatement.setRef(parameterIndex, x); 186 | } 187 | 188 | @Override 189 | public void setBlob(int parameterIndex, Blob x) throws SQLException { 190 | preparedStatement.setBlob(parameterIndex, x); 191 | } 192 | 193 | @Override 194 | public void setClob(int parameterIndex, Clob x) throws SQLException { 195 | preparedStatement.setClob(parameterIndex, x); 196 | } 197 | 198 | @Override 199 | public void setArray(int parameterIndex, Array x) throws SQLException { 200 | preparedStatement.setArray(parameterIndex, x); 201 | } 202 | 203 | @Override 204 | public ResultSetMetaData getMetaData() throws SQLException { 205 | return preparedStatement.getMetaData(); 206 | } 207 | 208 | @Override 209 | public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { 210 | preparedStatement.setDate(parameterIndex, x, cal); 211 | } 212 | 213 | @Override 214 | public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { 215 | preparedStatement.setTime(parameterIndex, x, cal); 216 | } 217 | 218 | @Override 219 | public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { 220 | preparedStatement.setTimestamp(parameterIndex, x, cal); 221 | } 222 | 223 | @Override 224 | public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { 225 | preparedStatement.setNull(parameterIndex, sqlType, typeName); 226 | } 227 | 228 | @Override 229 | public void setURL(int parameterIndex, URL x) throws SQLException { 230 | preparedStatement.setURL(parameterIndex, x); 231 | } 232 | 233 | @Override 234 | public ParameterMetaData getParameterMetaData() throws SQLException { 235 | return preparedStatement.getParameterMetaData(); 236 | } 237 | 238 | @Override 239 | public void setRowId(int parameterIndex, RowId x) throws SQLException { 240 | preparedStatement.setRowId(parameterIndex, x); 241 | } 242 | 243 | @Override 244 | public void setNString(int parameterIndex, String value) throws SQLException { 245 | preparedStatement.setNString(parameterIndex, value); 246 | } 247 | 248 | @Override 249 | public void setNCharacterStream(int parameterIndex, Reader value, long length) 250 | throws SQLException { 251 | preparedStatement.setNCharacterStream(parameterIndex, value, length); 252 | } 253 | 254 | @Override 255 | public void setNClob(int parameterIndex, NClob value) throws SQLException { 256 | preparedStatement.setNClob(parameterIndex, value); 257 | } 258 | 259 | @Override 260 | public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { 261 | preparedStatement.setClob(parameterIndex, reader, length); 262 | } 263 | 264 | @Override 265 | public void setBlob(int parameterIndex, InputStream inputStream, long length) 266 | throws SQLException { 267 | preparedStatement.setBlob(parameterIndex, inputStream, length); 268 | } 269 | 270 | @Override 271 | public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { 272 | preparedStatement.setNClob(parameterIndex, reader, length); 273 | } 274 | 275 | @Override 276 | public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { 277 | preparedStatement.setSQLXML(parameterIndex, xmlObject); 278 | } 279 | 280 | @Override 281 | public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) 282 | throws SQLException { 283 | preparedStatement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); 284 | } 285 | 286 | @Override 287 | public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { 288 | preparedStatement.setAsciiStream(parameterIndex, x, length); 289 | } 290 | 291 | @Override 292 | public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { 293 | preparedStatement.setBinaryStream(parameterIndex, x, length); 294 | } 295 | 296 | @Override 297 | public void setCharacterStream(int parameterIndex, Reader reader, long length) 298 | throws SQLException { 299 | preparedStatement.setCharacterStream(parameterIndex, reader, length); 300 | } 301 | 302 | @Override 303 | public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { 304 | preparedStatement.setAsciiStream(parameterIndex, x); 305 | } 306 | 307 | @Override 308 | public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { 309 | preparedStatement.setBinaryStream(parameterIndex, x); 310 | } 311 | 312 | @Override 313 | public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { 314 | preparedStatement.setCharacterStream(parameterIndex, reader); 315 | } 316 | 317 | @Override 318 | public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { 319 | preparedStatement.setNCharacterStream(parameterIndex, value); 320 | } 321 | 322 | @Override 323 | public void setClob(int parameterIndex, Reader reader) throws SQLException { 324 | preparedStatement.setClob(parameterIndex, reader); 325 | } 326 | 327 | @Override 328 | public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { 329 | preparedStatement.setBlob(parameterIndex, inputStream); 330 | } 331 | 332 | @Override 333 | public void setNClob(int parameterIndex, Reader reader) throws SQLException { 334 | preparedStatement.setNClob(parameterIndex, reader); 335 | } 336 | 337 | } 338 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/TracingStatement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import io.opentracing.Tracer; 18 | import java.sql.Connection; 19 | import java.sql.ResultSet; 20 | import java.sql.SQLException; 21 | import java.sql.SQLWarning; 22 | import java.sql.Statement; 23 | import java.util.ArrayList; 24 | import java.util.Set; 25 | 26 | public class TracingStatement implements Statement { 27 | 28 | private final Statement statement; 29 | private final String query; 30 | private final ArrayList batchCommands = new ArrayList<>(); 31 | final ConnectionInfo connectionInfo; 32 | final boolean withActiveSpanOnly; 33 | final Set ignoreStatements; 34 | final Tracer tracer; 35 | 36 | TracingStatement(Statement statement, ConnectionInfo connectionInfo, boolean withActiveSpanOnly, 37 | Set ignoreStatements, Tracer tracer) { 38 | this(statement, null, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 39 | } 40 | 41 | TracingStatement(Statement statement, String query, ConnectionInfo connectionInfo, 42 | boolean withActiveSpanOnly, Set ignoreStatements, Tracer tracer) { 43 | this.statement = statement; 44 | this.query = query; 45 | this.connectionInfo = connectionInfo; 46 | this.withActiveSpanOnly = withActiveSpanOnly; 47 | this.ignoreStatements = ignoreStatements; 48 | this.tracer = tracer; 49 | } 50 | 51 | @Override 52 | public ResultSet executeQuery(String sql) throws SQLException { 53 | return JdbcTracingUtils.call("Query", () -> statement.executeQuery(sql), 54 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 55 | } 56 | 57 | @Override 58 | public int executeUpdate(String sql) throws SQLException { 59 | return JdbcTracingUtils.call("Update", () -> statement.executeUpdate(sql), 60 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 61 | } 62 | 63 | @Override 64 | public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { 65 | return JdbcTracingUtils.call("Update", () -> statement.executeUpdate(sql, autoGeneratedKeys), 66 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 67 | } 68 | 69 | @Override 70 | public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { 71 | return JdbcTracingUtils.call("Update", () -> statement.executeUpdate(sql, columnIndexes), 72 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 73 | } 74 | 75 | @Override 76 | public int executeUpdate(String sql, String[] columnNames) throws SQLException { 77 | return JdbcTracingUtils.call("Update", () -> statement.executeUpdate(sql, columnNames), 78 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 79 | } 80 | 81 | @Override 82 | public boolean execute(String sql) throws SQLException { 83 | return JdbcTracingUtils.call("Execute", () -> statement.execute(sql), 84 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 85 | } 86 | 87 | @Override 88 | public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { 89 | return JdbcTracingUtils.call("Execute", () -> statement.execute(sql, autoGeneratedKeys), 90 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 91 | } 92 | 93 | @Override 94 | public boolean execute(String sql, int[] columnIndexes) throws SQLException { 95 | return JdbcTracingUtils.call("Execute", () -> statement.execute(sql, columnIndexes), 96 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 97 | } 98 | 99 | @Override 100 | public boolean execute(String sql, String[] columnNames) throws SQLException { 101 | return JdbcTracingUtils.call("Execute", () -> statement.execute(sql, columnNames), 102 | sql, connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 103 | } 104 | 105 | @Override 106 | public int[] executeBatch() throws SQLException { 107 | return JdbcTracingUtils.call("Update", statement::executeBatch, 108 | buildSqlForBatch(), connectionInfo, withActiveSpanOnly, ignoreStatements, tracer); 109 | } 110 | 111 | @Override 112 | public void close() throws SQLException { 113 | statement.close(); 114 | } 115 | 116 | @Override 117 | public int getMaxFieldSize() throws SQLException { 118 | return statement.getMaxFieldSize(); 119 | } 120 | 121 | @Override 122 | public void setMaxFieldSize(int max) throws SQLException { 123 | statement.setMaxFieldSize(max); 124 | } 125 | 126 | @Override 127 | public int getMaxRows() throws SQLException { 128 | return statement.getMaxRows(); 129 | } 130 | 131 | @Override 132 | public void setMaxRows(int max) throws SQLException { 133 | statement.setMaxRows(max); 134 | } 135 | 136 | @Override 137 | public void setEscapeProcessing(boolean enable) throws SQLException { 138 | statement.setEscapeProcessing(enable); 139 | } 140 | 141 | @Override 142 | public int getQueryTimeout() throws SQLException { 143 | return statement.getQueryTimeout(); 144 | } 145 | 146 | @Override 147 | public void setQueryTimeout(int seconds) throws SQLException { 148 | statement.setQueryTimeout(seconds); 149 | } 150 | 151 | @Override 152 | public void cancel() throws SQLException { 153 | statement.cancel(); 154 | } 155 | 156 | @Override 157 | public SQLWarning getWarnings() throws SQLException { 158 | return statement.getWarnings(); 159 | } 160 | 161 | @Override 162 | public void clearWarnings() throws SQLException { 163 | statement.clearWarnings(); 164 | } 165 | 166 | @Override 167 | public void setCursorName(String name) throws SQLException { 168 | statement.setCursorName(name); 169 | } 170 | 171 | @Override 172 | public ResultSet getResultSet() throws SQLException { 173 | return statement.getResultSet(); 174 | } 175 | 176 | @Override 177 | public int getUpdateCount() throws SQLException { 178 | return statement.getUpdateCount(); 179 | } 180 | 181 | @Override 182 | public boolean getMoreResults() throws SQLException { 183 | return statement.getMoreResults(); 184 | } 185 | 186 | @Override 187 | public void setFetchDirection(int direction) throws SQLException { 188 | statement.setFetchDirection(direction); 189 | } 190 | 191 | @Override 192 | public int getFetchDirection() throws SQLException { 193 | return statement.getFetchDirection(); 194 | } 195 | 196 | @Override 197 | public void setFetchSize(int rows) throws SQLException { 198 | statement.setFetchSize(rows); 199 | } 200 | 201 | @Override 202 | public int getFetchSize() throws SQLException { 203 | return statement.getFetchSize(); 204 | } 205 | 206 | @Override 207 | public int getResultSetConcurrency() throws SQLException { 208 | return statement.getResultSetConcurrency(); 209 | } 210 | 211 | @Override 212 | public int getResultSetType() throws SQLException { 213 | return statement.getResultSetType(); 214 | } 215 | 216 | @Override 217 | public void addBatch(String sql) throws SQLException { 218 | statement.addBatch(sql); 219 | batchCommands.add(sql); 220 | } 221 | 222 | @Override 223 | public void clearBatch() throws SQLException { 224 | statement.clearBatch(); 225 | batchCommands.clear(); 226 | } 227 | 228 | @Override 229 | public Connection getConnection() throws SQLException { 230 | return statement.getConnection(); 231 | } 232 | 233 | @Override 234 | public boolean getMoreResults(int current) throws SQLException { 235 | return statement.getMoreResults(current); 236 | } 237 | 238 | @Override 239 | public ResultSet getGeneratedKeys() throws SQLException { 240 | return statement.getGeneratedKeys(); 241 | } 242 | 243 | @Override 244 | public int getResultSetHoldability() throws SQLException { 245 | return statement.getResultSetHoldability(); 246 | } 247 | 248 | @Override 249 | public boolean isClosed() throws SQLException { 250 | return statement.isClosed(); 251 | } 252 | 253 | @Override 254 | public void setPoolable(boolean poolable) throws SQLException { 255 | statement.setPoolable(poolable); 256 | } 257 | 258 | @Override 259 | public boolean isPoolable() throws SQLException { 260 | return statement.isPoolable(); 261 | } 262 | 263 | @Override 264 | public void closeOnCompletion() throws SQLException { 265 | statement.closeOnCompletion(); 266 | } 267 | 268 | @Override 269 | public boolean isCloseOnCompletion() throws SQLException { 270 | return statement.isCloseOnCompletion(); 271 | } 272 | 273 | @Override 274 | public T unwrap(Class iface) throws SQLException { 275 | return statement.unwrap(iface); 276 | } 277 | 278 | @Override 279 | public boolean isWrapperFor(Class iface) throws SQLException { 280 | return statement.isWrapperFor(iface); 281 | } 282 | 283 | public String getQuery() { 284 | return query; 285 | } 286 | 287 | @Override 288 | public String toString() { 289 | return getQuery(); 290 | } 291 | 292 | private String buildSqlForBatch() { 293 | StringBuilder sqlBuilder = new StringBuilder(); 294 | if (query != null) { 295 | sqlBuilder.append(query); 296 | } 297 | 298 | for (String batchCommand : batchCommands) { 299 | sqlBuilder.append(batchCommand); 300 | } 301 | 302 | return sqlBuilder.toString(); 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/AS400URLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | 17 | import java.util.regex.Pattern; 18 | 19 | 20 | /** 21 | * Parser for AS400 22 | * 23 | * @author oburgosm 24 | * @since 0.2.12 25 | */ 26 | public class AS400URLParser extends AbstractMatcherURLParser { 27 | 28 | private static final Pattern AS400_URL_PATTERN = Pattern 29 | .compile( 30 | "jdbc:as400:\\/\\/(?[^\\/;]+)(\\/(?[^;\\/]*))?\\/?(;(?.*))?"); 31 | 32 | private static final String AS400_TYPE = "as400"; 33 | 34 | public AS400URLParser() { 35 | super(AS400_URL_PATTERN, AS400_TYPE); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/AbstractMatcherURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | /** 21 | * Parser based on regular expression 22 | * 23 | * @author oburgosm 24 | * @since 0.2.12 25 | */ 26 | public abstract class AbstractMatcherURLParser implements ConnectionURLParser { 27 | 28 | private final Pattern pattern; 29 | 30 | private final String dbType; 31 | 32 | public AbstractMatcherURLParser(Pattern pattern, String dbType) { 33 | this.pattern = pattern; 34 | this.dbType = dbType; 35 | } 36 | 37 | /** 38 | * Useful to modify ConnectionInfo before build 39 | * 40 | * @param matcher The matcher to apply. Note that the matcher must have a group named host, and 41 | * optionally, a group named port and another named instance 42 | * @return 43 | */ 44 | protected ConnectionInfo.Builder initBuilder(Matcher matcher) { 45 | String host = matcher.group("host"); 46 | String port = null; 47 | try { 48 | port = matcher.group("port"); 49 | } catch (IllegalArgumentException e) { 50 | // The pattern has no instance port 51 | } 52 | ConnectionInfo.Builder builder; 53 | if (port == null || "".equals(port)) { 54 | builder = new ConnectionInfo.Builder(host); 55 | } else { 56 | builder = new ConnectionInfo.Builder(host, Integer.valueOf(port)); 57 | } 58 | String instance = ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance(); 59 | try { 60 | instance = matcher.group("instance"); 61 | if (instance == null || "".equals(instance)) { 62 | instance = ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance(); 63 | } 64 | } catch (IllegalArgumentException e) { 65 | // The pattern has no instance group 66 | } 67 | return builder 68 | .dbType(this.dbType) 69 | .dbInstance(instance); 70 | } 71 | 72 | 73 | @Override 74 | public ConnectionInfo parse(String url) { 75 | Matcher matcher = this.pattern.matcher(url); 76 | if (matcher.matches()) { 77 | return this.initBuilder(matcher).build(); 78 | } else { 79 | return ConnectionInfo.UNKNOWN_CONNECTION_INFO; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/AbstractURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | public abstract class AbstractURLParser implements ConnectionURLParser { 17 | 18 | /** 19 | * Fetch the index range that database host and port from connection url. 20 | * 21 | * @return index range that database hosts. 22 | */ 23 | protected abstract URLLocation fetchDatabaseHostsIndexRange(final String url); 24 | 25 | /** 26 | * Fetch the index range that database name from connection url. 27 | * 28 | * @return index range that database name. 29 | */ 30 | protected abstract URLLocation fetchDatabaseNameIndexRange(final String url); 31 | 32 | /** 33 | * Fetch database host(s) from connection url. 34 | * 35 | * @return database host(s). 36 | */ 37 | protected String fetchDatabaseHostsFromURL(String url) { 38 | URLLocation hostsLocation = fetchDatabaseHostsIndexRange(url); 39 | return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex()); 40 | } 41 | 42 | /** 43 | * Fetch database name from connection url. 44 | * 45 | * @return database name. 46 | */ 47 | protected String fetchDatabaseNameFromURL(String url) { 48 | URLLocation hostsLocation = fetchDatabaseNameIndexRange(url); 49 | return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex()); 50 | } 51 | 52 | /** 53 | * Fetch database name from connection url. 54 | * 55 | * @return database name. 56 | */ 57 | protected String fetchDatabaseNameFromURL(String url, int[] indexRange) { 58 | return url.substring(indexRange[0], indexRange[1]); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/ConnectionURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | 18 | public interface ConnectionURLParser { 19 | ConnectionInfo parse(final String url); 20 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/DB2URLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import java.util.regex.Pattern; 17 | 18 | 19 | /** 20 | * Parser for DB2 21 | * 22 | * @author oburgosm 23 | * @since 0.2.12 24 | */ 25 | public class DB2URLParser extends AbstractMatcherURLParser { 26 | 27 | 28 | private static final Pattern DB2_URL_PATTERN = Pattern 29 | .compile( 30 | "jdbc:db2:\\/\\/(?[^:\\/]+)(:(?\\d+))?\\/(?[^:]+)(:(?.*))?"); 31 | 32 | private static final String DB2_TYPE = "db2"; 33 | 34 | public DB2URLParser() { 35 | super(DB2_URL_PATTERN, DB2_TYPE); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/H2URLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | 18 | public class H2URLParser extends AbstractURLParser { 19 | 20 | private static final String LOCALHOST = "localhost"; 21 | private static final int DEFAULT_PORT = 8084; 22 | /** 23 | * Flag that H2 running with memory mode. 24 | */ 25 | private static final String MEMORY_MODE_FLAG = "mem"; 26 | /** 27 | * Flag that H2 running with tcp mode. 28 | */ 29 | private static final String TCP_MODE_FLAG = "h2:tcp"; 30 | /** 31 | * Flag that H2 running with file mode. 32 | */ 33 | private static final String FILE_MODE_FLAG = "file"; 34 | /** 35 | * Flag that H2 running with implicit file mode. 36 | */ 37 | private static final String IMPLICIT_FILE_MODE_FLAG = "jdbc:h2"; 38 | private static final String H2_DB_TYPE = "h2"; 39 | 40 | @Override 41 | protected URLLocation fetchDatabaseHostsIndexRange(String url) { 42 | int hostLabelStartIndex = url.indexOf("//"); 43 | int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2); 44 | return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex); 45 | } 46 | 47 | @Override 48 | protected URLLocation fetchDatabaseNameIndexRange(String url) { 49 | int databaseStartTag = url.lastIndexOf("/"); 50 | int databaseEndTag = url.indexOf(";"); 51 | if (databaseEndTag == -1) { 52 | databaseEndTag = url.length(); 53 | } 54 | return new URLLocation(databaseStartTag + 1, databaseEndTag); 55 | } 56 | 57 | @Override 58 | public ConnectionInfo parse(String url) { 59 | int[] databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2FileMode(url); 60 | if (databaseNameRangeIndex != null) { 61 | return new ConnectionInfo.Builder(LOCALHOST, -1).dbType(H2_DB_TYPE) 62 | .dbInstance(fetchDatabaseNameFromURL(url, databaseNameRangeIndex)).build(); 63 | } 64 | 65 | databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2MemMode(url); 66 | if (databaseNameRangeIndex != null) { 67 | return new ConnectionInfo.Builder(LOCALHOST, -1).dbType(H2_DB_TYPE) 68 | .dbInstance(fetchDatabaseNameFromURL(url, databaseNameRangeIndex)).build(); 69 | } 70 | 71 | databaseNameRangeIndex = fetchDatabaseNameRangeIndexFromURLForH2ImplicitFileMode(url); 72 | if (databaseNameRangeIndex != null) { 73 | return new ConnectionInfo.Builder(LOCALHOST, -1).dbType(H2_DB_TYPE) 74 | .dbInstance(fetchDatabaseNameFromURL(url, databaseNameRangeIndex)).build(); 75 | } 76 | 77 | String[] hostAndPort = fetchDatabaseHostsFromURL(url).split(":"); 78 | if (hostAndPort.length == 1) { 79 | return new ConnectionInfo.Builder(hostAndPort[0], DEFAULT_PORT).dbType(H2_DB_TYPE) 80 | .dbInstance(fetchDatabaseNameFromURL(url)).build(); 81 | } else { 82 | return new ConnectionInfo.Builder(hostAndPort[0], Integer.valueOf(hostAndPort[1])) 83 | .dbType(H2_DB_TYPE).dbInstance(fetchDatabaseNameFromURL(url)).build(); 84 | } 85 | } 86 | 87 | /** 88 | * Fetch range index that the database name from connection url if H2 database running with file 89 | * mode. 90 | * 91 | * @return range index that the database name. 92 | */ 93 | private int[] fetchDatabaseNameRangeIndexFromURLForH2FileMode(String url) { 94 | int fileLabelIndex = url.indexOf(FILE_MODE_FLAG); 95 | int parameterLabelIndex = url.indexOf(";", fileLabelIndex); 96 | if (parameterLabelIndex == -1) { 97 | parameterLabelIndex = url.length(); 98 | } 99 | 100 | if (fileLabelIndex != -1) { 101 | return new int[]{fileLabelIndex + FILE_MODE_FLAG.length() + 1, parameterLabelIndex}; 102 | } else { 103 | return null; 104 | } 105 | } 106 | 107 | /** 108 | * Fetch range index that the database name from connection url if H2 database running with 109 | * implicit file mode. 110 | * 111 | * @return range index that the database name. 112 | */ 113 | private int[] fetchDatabaseNameRangeIndexFromURLForH2ImplicitFileMode(String url) { 114 | if (url.contains(TCP_MODE_FLAG)) { 115 | return null; 116 | } 117 | int fileLabelIndex = url.indexOf(IMPLICIT_FILE_MODE_FLAG); 118 | int parameterLabelIndex = url.indexOf(";", fileLabelIndex); 119 | if (parameterLabelIndex == -1) { 120 | parameterLabelIndex = url.length(); 121 | } 122 | 123 | if (fileLabelIndex != -1) { 124 | return new int[]{fileLabelIndex + IMPLICIT_FILE_MODE_FLAG.length() + 1, parameterLabelIndex}; 125 | } else { 126 | return null; 127 | } 128 | } 129 | 130 | /** 131 | * Fetch range index that the database name from connection url if H2 database running with memory 132 | * mode. 133 | * 134 | * @return range index that the database name. 135 | */ 136 | private int[] fetchDatabaseNameRangeIndexFromURLForH2MemMode(String url) { 137 | int fileLabelIndex = url.indexOf(MEMORY_MODE_FLAG); 138 | int parameterLabelIndex = url.indexOf(";", fileLabelIndex); 139 | if (parameterLabelIndex == -1) { 140 | parameterLabelIndex = url.length(); 141 | } 142 | 143 | if (fileLabelIndex != -1) { 144 | return new int[]{fileLabelIndex + MEMORY_MODE_FLAG.length() + 1, parameterLabelIndex}; 145 | } else { 146 | return null; 147 | } 148 | } 149 | 150 | 151 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/MariadbURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | public class MariadbURLParser extends MysqlURLParser { 17 | 18 | protected String dbType() { 19 | return "mariadb"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/MysqlURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | 18 | public class MysqlURLParser extends AbstractURLParser { 19 | 20 | private static final String DEFAULT_HOST = "localhost"; 21 | 22 | private static final int DEFAULT_PORT = 3306; 23 | 24 | protected String dbType() { 25 | return "mysql"; 26 | } 27 | 28 | @Override 29 | protected URLLocation fetchDatabaseHostsIndexRange(String url) { 30 | int hostLabelStartIndex = url.indexOf("//") + 2; 31 | int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex); 32 | if (hostLabelEndIndex == -1) { 33 | int queryStringStartIndex = url.indexOf("?", hostLabelStartIndex); 34 | if (queryStringStartIndex == -1) { 35 | hostLabelEndIndex = url.length(); 36 | } else { 37 | hostLabelEndIndex = queryStringStartIndex; 38 | } 39 | } 40 | return new URLLocation(hostLabelStartIndex, hostLabelEndIndex); 41 | } 42 | 43 | protected String fetchDatabaseNameFromURL(String url, int startSize) { 44 | URLLocation hostsLocation = fetchDatabaseNameIndexRange(url, startSize); 45 | if (hostsLocation == null) { 46 | return ""; 47 | } 48 | return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex()); 49 | } 50 | 51 | protected URLLocation fetchDatabaseNameIndexRange(String url, int startSize) { 52 | int databaseStartTag = url.indexOf("/", startSize); 53 | if (databaseStartTag == -1) { 54 | return null; 55 | } 56 | int databaseEndTag = url.indexOf("?", databaseStartTag); 57 | if (databaseEndTag == -1) { 58 | databaseEndTag = url.length(); 59 | } 60 | return new URLLocation(databaseStartTag + 1, databaseEndTag); 61 | } 62 | 63 | @Override 64 | protected URLLocation fetchDatabaseNameIndexRange(String url) { 65 | int databaseStartTag = url.lastIndexOf("/"); 66 | int databaseEndTag = url.indexOf("?", databaseStartTag); 67 | if (databaseEndTag == -1) { 68 | databaseEndTag = url.length(); 69 | } 70 | return new URLLocation(databaseStartTag + 1, databaseEndTag); 71 | } 72 | 73 | @Override 74 | public ConnectionInfo parse(String url) { 75 | URLLocation location = fetchDatabaseHostsIndexRange(url); 76 | String hosts = url.substring(location.startIndex(), location.endIndex()); 77 | if (hosts.isEmpty()) { 78 | hosts = DEFAULT_HOST; 79 | } 80 | String[] hostSegment = hosts.split(","); 81 | if (hostSegment.length > 1) { 82 | StringBuilder sb = new StringBuilder(); 83 | for (String host : hostSegment) { 84 | if (host.split(":").length == 1) { 85 | sb.append(host + ":" + DEFAULT_PORT + ","); 86 | } else { 87 | sb.append(host + ","); 88 | } 89 | } 90 | if (',' == sb.charAt(sb.length() - 1)) { 91 | sb.deleteCharAt(sb.length() - 1); 92 | } 93 | return new ConnectionInfo.Builder(sb.toString()).dbType(dbType()) 94 | .dbInstance(fetchDatabaseNameFromURL(url)).build(); 95 | } else { 96 | String[] hostAndPort = hostSegment[0].split(":"); 97 | if (hostAndPort.length != 1) { 98 | return new ConnectionInfo.Builder(hostAndPort[0], Integer.valueOf(hostAndPort[1])) 99 | .dbType(dbType()).dbInstance(fetchDatabaseNameFromURL(url, location.endIndex())) 100 | .build(); 101 | } else { 102 | 103 | return new ConnectionInfo.Builder(hostAndPort[0], DEFAULT_PORT).dbType(dbType()) 104 | .dbInstance(fetchDatabaseNameFromURL(url, location.endIndex())).build(); 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/OracleURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.regex.Matcher; 19 | import java.util.regex.Pattern; 20 | 21 | import io.opentracing.contrib.jdbc.ConnectionInfo; 22 | 23 | public class OracleURLParser implements ConnectionURLParser { 24 | public static final String DB_TYPE = "oracle"; 25 | public static final String PREFIX_THIN = "jdbc:oracle:thin:"; 26 | public static final String PREFIX_OCI = "jdbc:oracle:oci:"; 27 | public static final int DEFAULT_PORT = 1521; 28 | private static Pattern EASY_CONNECT_PATTERN = Pattern.compile( 29 | "(?.*)@(?ldap:)?(//)?(?[^:/]+)(?:[0-9]+)?(?[:/][^:/]+)?(?:[^:/]+)?(?/[^:/]+)?"); 30 | 31 | @Override 32 | public ConnectionInfo parse(final String url) { 33 | if (url!= null) { 34 | String lowerCaseUrl = url.toLowerCase(); 35 | if ((lowerCaseUrl.startsWith(PREFIX_THIN) || lowerCaseUrl.startsWith(PREFIX_OCI))) { 36 | String trimmedURL; 37 | if (lowerCaseUrl.startsWith(PREFIX_THIN)) { 38 | trimmedURL = url.substring(PREFIX_THIN.length()); 39 | } else { 40 | trimmedURL = url.substring(PREFIX_OCI.length()); 41 | } 42 | OracleConnectionInfo connectionInfo = parseTnsName(trimmedURL); 43 | if (connectionInfo == null) { 44 | connectionInfo = parseEasyConnect(trimmedURL); 45 | } 46 | if (connectionInfo != null) { 47 | return new ConnectionInfo.Builder(connectionInfo.getDbPeer()) // 48 | .dbType(DB_TYPE) // 49 | .dbInstance(connectionInfo.getDbInstance()) // 50 | .build(); 51 | } 52 | } 53 | } 54 | return null; 55 | } 56 | 57 | private OracleConnectionInfo parseTnsName(final String url) { 58 | final String hosts = parseDatabaseHostsFromTnsUrl(url); 59 | if (hosts != null) { 60 | final int idxServiceName = url.indexOf("SERVICE_NAME"); 61 | final int start = url.indexOf('=', idxServiceName) + 1; 62 | final int end = url.indexOf(")", start); 63 | final String serviceName = url.substring(start, end); 64 | return new OracleConnectionInfo() // 65 | .setDbPeer(hosts) // 66 | .setDbInstance(serviceName); 67 | } 68 | return null; 69 | } 70 | 71 | public static String parseDatabaseHostsFromTnsUrl(String url) { 72 | int beginIndex = url.indexOf("DESCRIPTION"); 73 | if (beginIndex == -1) { 74 | return null; 75 | } 76 | List hosts = new ArrayList(); 77 | do { 78 | int hostStartIndex = url.indexOf("HOST", beginIndex); 79 | if (hostStartIndex == -1) { 80 | break; 81 | } 82 | int equalStartIndex = url.indexOf("=", hostStartIndex); 83 | int hostEndIndex = url.indexOf(")", hostStartIndex); 84 | String host = url.substring(equalStartIndex + 1, hostEndIndex); 85 | 86 | int port = DEFAULT_PORT; 87 | int portStartIndex = url.indexOf("PORT", hostEndIndex); 88 | int portEndIndex = url.length(); 89 | if (portStartIndex != -1) { 90 | int portEqualStartIndex = url.indexOf("=", portStartIndex); 91 | portEndIndex = url.indexOf(")", portEqualStartIndex); 92 | port = Integer.parseInt(url.substring(portEqualStartIndex + 1, portEndIndex).trim()); 93 | } 94 | hosts.add(host.trim() + ":" + port); 95 | beginIndex = portEndIndex; 96 | } while (true); 97 | return join(",", hosts); 98 | } 99 | 100 | private static String join(String delimiter, List list) { 101 | if (list == null || list.isEmpty()) { 102 | return ""; 103 | } 104 | StringBuilder builder = new StringBuilder(); 105 | for (int i = 0, len = list.size(); i < len; i++) { 106 | if (i == (len - 1)) { 107 | builder.append(list.get(i)); 108 | } else { 109 | builder.append(list.get(i)).append(delimiter); 110 | } 111 | } 112 | return builder.toString(); 113 | } 114 | 115 | /** 116 | * Implementation according to https://www.oracle.com/technetwork/database/enterprise-edition/oraclenetservices-neteasyconnect-133058.pdf 117 | * 118 | * @param url the url without the oracle jdbc prefix 119 | * @return the oracle connection info if the url could be parsed, or null otherwise. 120 | */ 121 | public static OracleConnectionInfo parseEasyConnect(final String url) { 122 | final Matcher matcher = EASY_CONNECT_PATTERN.matcher(url); 123 | if (matcher.matches()) { 124 | final OracleConnectionInfo result = new OracleConnectionInfo(); 125 | final String host = matcher.group("host"); 126 | final String portGroup = matcher.group("port"); 127 | final int dbPort = 128 | portGroup != null ? Integer.parseInt(portGroup.substring(1)) : DEFAULT_PORT; 129 | result.setDbPeer(host + ":" + dbPort); 130 | final String service = matcher.group("service"); 131 | if (service != null) { 132 | result.setDbInstance(service.substring(1)); 133 | } else { 134 | result.setDbInstance(host); 135 | } 136 | return result; 137 | } 138 | return null; 139 | } 140 | 141 | public static class OracleConnectionInfo { 142 | private String dbInstance; 143 | private String dbPeer; 144 | 145 | public String getDbInstance() { 146 | return dbInstance; 147 | } 148 | 149 | public OracleConnectionInfo setDbInstance(final String dbInstance) { 150 | this.dbInstance = dbInstance; 151 | return this; 152 | } 153 | 154 | public String getDbPeer() { 155 | return dbPeer; 156 | } 157 | 158 | public OracleConnectionInfo setDbPeer(final String dbPeer) { 159 | this.dbPeer = dbPeer; 160 | return this; 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/PostgreSQLURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | import java.net.URI; 18 | import java.net.URISyntaxException; 19 | 20 | public class PostgreSQLURLParser extends AbstractURLParser { 21 | 22 | private static final int DEFAULT_PORT = 5432; 23 | private static final String DB_TYPE = "postgresql"; 24 | 25 | @Override 26 | protected URLLocation fetchDatabaseHostsIndexRange(String url) { 27 | int hostLabelStartIndex = url.indexOf("//"); 28 | int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2); 29 | return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex); 30 | } 31 | 32 | @Override 33 | protected URLLocation fetchDatabaseNameIndexRange(String url) { 34 | int hostLabelStartIndex = url.indexOf("//"); 35 | int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2); 36 | int databaseStartTag = url.indexOf("/", hostLabelEndIndex); 37 | int databaseEndTag = url.indexOf("?", databaseStartTag); 38 | if (databaseEndTag == -1) { 39 | databaseEndTag = url.length(); 40 | } 41 | return new URLLocation(databaseStartTag + 1, databaseEndTag); 42 | } 43 | 44 | @Override 45 | public ConnectionInfo parse(String url) { 46 | URLLocation location = fetchDatabaseHostsIndexRange(url); 47 | String hosts = url.substring(location.startIndex(), location.endIndex()); 48 | String[] hostSegment = hosts.split(","); 49 | if (hostSegment.length > 1) { 50 | StringBuilder sb = new StringBuilder(); 51 | for (String host : hostSegment) { 52 | URI uri = parseHost(host); 53 | int port = uri.getPort() == -1 ? DEFAULT_PORT : uri.getPort(); 54 | 55 | sb.append(uri.getHost() + ":" + port + ","); 56 | } 57 | if (',' == sb.charAt(sb.length() - 1)) { 58 | sb.deleteCharAt(sb.length() - 1); 59 | } 60 | return new ConnectionInfo.Builder(sb.toString()).dbType(DB_TYPE) 61 | .dbInstance(fetchDatabaseNameFromURL(url)).build(); 62 | } else { 63 | URI uri = parseHost(hostSegment[0]); 64 | int port = uri.getPort() == -1 ? DEFAULT_PORT : uri.getPort(); 65 | 66 | return new ConnectionInfo.Builder(uri.getHost(), port) 67 | .dbType(DB_TYPE).dbInstance(fetchDatabaseNameFromURL(url)).build(); 68 | } 69 | } 70 | 71 | private URI parseHost(String host) { 72 | try { 73 | return new URI("proto://" + host); 74 | } catch (URISyntaxException e) { 75 | throw new IllegalArgumentException(e); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/SqlServerURLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | import java.io.UnsupportedEncodingException; 18 | import java.net.URLDecoder; 19 | import java.nio.charset.StandardCharsets; 20 | import java.util.Collections; 21 | import java.util.LinkedHashMap; 22 | import java.util.Map; 23 | 24 | public class SqlServerURLParser implements ConnectionURLParser { 25 | 26 | private static final int DEFAULT_PORT = 1433; 27 | 28 | protected String dbType() { 29 | return "sqlserver"; 30 | } 31 | 32 | @Override 33 | public ConnectionInfo parse(String url) { 34 | String serverName = ""; 35 | Integer port = DEFAULT_PORT; 36 | String dbInstance = null; 37 | int hostIndex = url.indexOf("://"); 38 | if (hostIndex <= 0) { 39 | return null; 40 | } 41 | 42 | String[] split = url.split(";", 2); 43 | if (split.length > 1) { 44 | Map props = parseQueryParams(split[1], ";"); 45 | serverName = props.get("serverName"); 46 | dbInstance = props.get("databaseName"); 47 | if (props.containsKey("portNumber")) { 48 | String portNumber = props.get("portNumber"); 49 | try { 50 | port = Integer.parseInt(portNumber); 51 | } catch (NumberFormatException e) { 52 | } 53 | } 54 | } 55 | 56 | String urlServerName = split[0].substring(hostIndex + 3); 57 | if (!urlServerName.isEmpty()) { 58 | serverName = urlServerName; 59 | } 60 | 61 | int portLoc = serverName.indexOf(":"); 62 | if (portLoc > 1) { 63 | port = Integer.parseInt(serverName.substring(portLoc + 1)); 64 | serverName = serverName.substring(0, portLoc); 65 | } 66 | 67 | int instanceLoc = serverName.indexOf("\\"); 68 | if (instanceLoc > 1) { 69 | serverName = serverName.substring(0, instanceLoc); 70 | } 71 | 72 | if (serverName.isEmpty()) { 73 | return null; 74 | } 75 | 76 | return new ConnectionInfo.Builder(serverName, port).dbType(dbType()) 77 | .dbInstance(dbInstance).build(); 78 | } 79 | 80 | private Map parseQueryParams(String query, String separator) { 81 | if (query == null || query.isEmpty()) { 82 | return Collections.emptyMap(); 83 | } 84 | Map queryParams = new LinkedHashMap<>(); 85 | String[] pairs = query.split(separator); 86 | for (String pair : pairs) { 87 | try { 88 | int idx = pair.indexOf("="); 89 | String key = 90 | idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8.name()) 91 | : pair; 92 | if (!queryParams.containsKey(key)) { 93 | String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder 94 | .decode(pair.substring(idx + 1), StandardCharsets.UTF_8.name()) : null; 95 | queryParams.put(key, value); 96 | } 97 | } catch (UnsupportedEncodingException e) { 98 | // Ignore. 99 | } 100 | } 101 | return queryParams; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/URLLocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | public class URLLocation { 17 | private final int startIndex; 18 | private final int endIndex; 19 | 20 | public URLLocation(int startIndex, int endIndex) { 21 | this.startIndex = startIndex; 22 | this.endIndex = endIndex; 23 | } 24 | 25 | public int startIndex() { 26 | return startIndex; 27 | } 28 | 29 | public int endIndex() { 30 | return endIndex; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/io/opentracing/contrib/jdbc/parser/URLParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import io.opentracing.contrib.jdbc.ConnectionInfo; 17 | import java.util.LinkedHashMap; 18 | import java.util.Map; 19 | import java.util.logging.Level; 20 | import java.util.logging.Logger; 21 | 22 | public class URLParser { 23 | private static final Logger log = Logger.getLogger(URLParser.class.getName()); 24 | 25 | private static final String MYSQL_JDBC_URL_PREFIX = "jdbc:mysql"; 26 | private static final String ORACLE_JDBC_URL_PREFIX = "jdbc:oracle"; 27 | private static final String H2_JDBC_URL_PREFIX = "jdbc:h2"; 28 | private static final String POSTGRESQL_JDBC_URL_PREFIX = "jdbc:postgresql"; 29 | private static final String MARIADB_JDBC_URL_PREFIX = "jdbc:mariadb"; 30 | private static final String SQLSERVER_JDBC_URL_PREFIX = "jdbc:sqlserver"; 31 | private static final String DB2_JDBC_URL_PREFIX = "jdbc:db2"; 32 | private static final String AS400_JDBC_URL_PREFIX = "jdbc:as400"; 33 | private static final Map parserRegister = new LinkedHashMap<>(); 34 | 35 | static { 36 | // put mysql parser firstly 37 | parserRegister.put(MYSQL_JDBC_URL_PREFIX, new MysqlURLParser()); 38 | parserRegister.put(ORACLE_JDBC_URL_PREFIX, new OracleURLParser()); 39 | parserRegister.put(H2_JDBC_URL_PREFIX, new H2URLParser()); 40 | parserRegister.put(POSTGRESQL_JDBC_URL_PREFIX, new PostgreSQLURLParser()); 41 | parserRegister.put(MARIADB_JDBC_URL_PREFIX, new MariadbURLParser()); 42 | parserRegister.put(SQLSERVER_JDBC_URL_PREFIX, new SqlServerURLParser()); 43 | parserRegister.put(DB2_JDBC_URL_PREFIX, new DB2URLParser()); 44 | parserRegister.put(AS400_JDBC_URL_PREFIX, new AS400URLParser()); 45 | } 46 | 47 | /** 48 | * parse the url to the ConnectionInfo 49 | */ 50 | public static ConnectionInfo parse(String url) { 51 | if (null == url) { 52 | return ConnectionInfo.UNKNOWN_CONNECTION_INFO; 53 | } 54 | String lowerCaseUrl = url.toLowerCase(); 55 | ConnectionURLParser parser = findURLParser(lowerCaseUrl); 56 | if (parser == null) { 57 | return ConnectionInfo.UNKNOWN_CONNECTION_INFO; 58 | } 59 | try { 60 | return parser.parse(url); 61 | } catch (Exception e) { 62 | log.log(Level.WARNING, "error occurs when parsing jdbc url"); 63 | } 64 | return ConnectionInfo.UNKNOWN_CONNECTION_INFO; 65 | } 66 | 67 | /** 68 | * @deprecated use {@link #parse(String)} instead 69 | */ 70 | @Deprecated 71 | public static ConnectionInfo parser(String url) { 72 | return parse(url); 73 | } 74 | 75 | private static ConnectionURLParser findURLParser(String lowerCaseUrl) { 76 | for (Map.Entry entry : parserRegister.entrySet()) { 77 | if (lowerCaseUrl.startsWith(entry.getKey())) { 78 | return entry.getValue(); 79 | } 80 | } 81 | return null; 82 | } 83 | 84 | /** 85 | * register new ConnectionURLParser. Can override existing parser. 86 | */ 87 | public static void registerConnectionParser(String urlPrefix, ConnectionURLParser parser) { 88 | if (null == urlPrefix || parser == null) { 89 | throw new IllegalArgumentException("urlPrefix and parser can not be null"); 90 | } 91 | parserRegister.put(urlPrefix.toLowerCase(), parser); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | io.opentracing.contrib.jdbc.TracingDriver 2 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/HibernateTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import static io.opentracing.contrib.jdbc.TestUtil.checkNoEmptyTags; 18 | import static io.opentracing.contrib.jdbc.TestUtil.checkSameTrace; 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertNotNull; 22 | import static org.junit.Assert.assertNull; 23 | 24 | import io.opentracing.Scope; 25 | import io.opentracing.mock.MockSpan; 26 | import io.opentracing.mock.MockTracer; 27 | import io.opentracing.tag.Tags; 28 | import io.opentracing.util.GlobalTracerTestUtil; 29 | import io.opentracing.util.ThreadLocalScopeManager; 30 | import java.util.ArrayList; 31 | import java.util.Collections; 32 | import java.util.List; 33 | import javax.persistence.Column; 34 | import javax.persistence.Entity; 35 | import javax.persistence.EntityManager; 36 | import javax.persistence.EntityManagerFactory; 37 | import javax.persistence.GeneratedValue; 38 | import javax.persistence.GenerationType; 39 | import javax.persistence.Id; 40 | import javax.persistence.Persistence; 41 | import javax.persistence.Table; 42 | import org.hibernate.Session; 43 | import org.hibernate.SessionFactory; 44 | import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 45 | import org.hibernate.cfg.Configuration; 46 | import org.junit.Before; 47 | import org.junit.BeforeClass; 48 | import org.junit.Test; 49 | 50 | public class HibernateTest { 51 | 52 | private static final MockTracer mockTracer = new MockTracer(new ThreadLocalScopeManager(), 53 | MockTracer.Propagator.TEXT_MAP); 54 | 55 | @BeforeClass 56 | public static void init() { 57 | GlobalTracerTestUtil.setGlobalTracerUnconditionally(mockTracer); 58 | } 59 | 60 | @Before 61 | public void before() { 62 | mockTracer.reset(); 63 | } 64 | 65 | @Test 66 | public void jpa() { 67 | EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa"); 68 | 69 | Employee employee = new Employee(); 70 | EntityManager entityManager = entityManagerFactory.createEntityManager(); 71 | entityManager.getTransaction().begin(); 72 | entityManager.persist(employee); 73 | entityManager.getTransaction().commit(); 74 | entityManager.close(); 75 | entityManagerFactory.close(); 76 | 77 | assertNotNull(employee.id); 78 | 79 | List finishedSpans = mockTracer.finishedSpans(); 80 | assertEquals(14, finishedSpans.size()); 81 | 82 | checkSpans(finishedSpans, "jpa"); 83 | assertNull(mockTracer.activeSpan()); 84 | } 85 | 86 | @Test 87 | public void jpa_with_active_span_only() { 88 | EntityManagerFactory entityManagerFactory = Persistence 89 | .createEntityManagerFactory("jpa_active_span_only"); 90 | 91 | Employee employee = new Employee(); 92 | EntityManager entityManager = entityManagerFactory.createEntityManager(); 93 | entityManager.getTransaction().begin(); 94 | entityManager.persist(employee); 95 | entityManager.getTransaction().commit(); 96 | entityManager.close(); 97 | entityManagerFactory.close(); 98 | 99 | assertNotNull(employee.id); 100 | 101 | List finishedSpans = mockTracer.finishedSpans(); 102 | assertEquals(0, finishedSpans.size()); 103 | 104 | assertNull(mockTracer.activeSpan()); 105 | } 106 | 107 | @Test 108 | public void jpa_with_parent() { 109 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 110 | try (Scope ignored = mockTracer.activateSpan(parent)) { 111 | EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa"); 112 | 113 | EntityManager entityManager = entityManagerFactory.createEntityManager(); 114 | 115 | entityManager.getTransaction().begin(); 116 | entityManager.persist(new Employee()); 117 | entityManager.persist(new Employee()); 118 | entityManager.getTransaction().commit(); 119 | entityManager.close(); 120 | entityManagerFactory.close(); 121 | } 122 | parent.finish(); 123 | 124 | List spans = mockTracer.finishedSpans(); 125 | assertEquals(17, spans.size()); 126 | checkSameTrace(spans); 127 | assertNull(mockTracer.activeSpan()); 128 | } 129 | 130 | @Test 131 | public void jpa_with_parent_and_active_span_only() { 132 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 133 | try (Scope ignored = mockTracer.activateSpan(parent)) { 134 | EntityManagerFactory entityManagerFactory = Persistence 135 | .createEntityManagerFactory("jpa_active_span_only"); 136 | 137 | EntityManager entityManager = entityManagerFactory.createEntityManager(); 138 | 139 | entityManager.getTransaction().begin(); 140 | entityManager.persist(new Employee()); 141 | entityManager.persist(new Employee()); 142 | entityManager.getTransaction().commit(); 143 | entityManager.close(); 144 | entityManagerFactory.close(); 145 | } 146 | parent.finish(); 147 | 148 | List spans = mockTracer.finishedSpans(); 149 | assertEquals(17, spans.size()); 150 | checkSameTrace(spans); 151 | assertNull(mockTracer.activeSpan()); 152 | } 153 | 154 | @Test 155 | public void hibernate() { 156 | SessionFactory sessionFactory = createSessionFactory(false); 157 | Session session = sessionFactory.openSession(); 158 | 159 | Employee employee = new Employee(); 160 | session.beginTransaction(); 161 | session.save(employee); 162 | session.getTransaction().commit(); 163 | session.close(); 164 | sessionFactory.close(); 165 | 166 | assertNotNull(employee.id); 167 | 168 | List finishedSpans = mockTracer.finishedSpans(); 169 | assertEquals(14, finishedSpans.size()); 170 | 171 | checkSpans(finishedSpans, "hibernate"); 172 | assertNull(mockTracer.activeSpan()); 173 | } 174 | 175 | @Test 176 | public void hibernate_with_active_span_only() { 177 | SessionFactory sessionFactory = createSessionFactory(true); 178 | Session session = sessionFactory.openSession(); 179 | 180 | Employee employee = new Employee(); 181 | session.beginTransaction(); 182 | session.save(employee); 183 | session.getTransaction().commit(); 184 | session.close(); 185 | sessionFactory.close(); 186 | 187 | assertNotNull(employee.id); 188 | 189 | List finishedSpans = mockTracer.finishedSpans(); 190 | assertEquals(0, finishedSpans.size()); 191 | 192 | assertNull(mockTracer.activeSpan()); 193 | } 194 | 195 | @Test 196 | public void hibernate_with_parent() { 197 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 198 | try (Scope ignored = mockTracer.activateSpan(parent)) { 199 | SessionFactory sessionFactory = createSessionFactory(false); 200 | Session session = sessionFactory.openSession(); 201 | 202 | session.beginTransaction(); 203 | session.save(new Employee()); 204 | session.save(new Employee()); 205 | session.getTransaction().commit(); 206 | session.close(); 207 | sessionFactory.close(); 208 | } 209 | parent.finish(); 210 | 211 | List spans = mockTracer.finishedSpans(); 212 | assertEquals(17, spans.size()); 213 | checkSameTrace(spans); 214 | assertNull(mockTracer.activeSpan()); 215 | } 216 | 217 | @Test 218 | public void hibernate_with_parent_and_active_span_only() { 219 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 220 | try (Scope ignored = mockTracer.activateSpan(parent)) { 221 | SessionFactory sessionFactory = createSessionFactory(true); 222 | Session session = sessionFactory.openSession(); 223 | 224 | session.beginTransaction(); 225 | session.save(new Employee()); 226 | session.save(new Employee()); 227 | session.getTransaction().commit(); 228 | session.close(); 229 | sessionFactory.close(); 230 | } 231 | parent.finish(); 232 | 233 | List spans = mockTracer.finishedSpans(); 234 | assertEquals(17, spans.size()); 235 | checkSameTrace(spans); 236 | assertNull(mockTracer.activeSpan()); 237 | } 238 | 239 | @Test 240 | public void hibernate_with_ignored_statement() { 241 | SessionFactory sessionFactory = createSessionFactory(false, 242 | Collections.singletonList("insert into Employee (id) values (?)")); 243 | Session session = sessionFactory.openSession(); 244 | 245 | Employee employee = new Employee(); 246 | session.beginTransaction(); 247 | session.save(employee); 248 | session.getTransaction().commit(); 249 | session.close(); 250 | sessionFactory.close(); 251 | 252 | assertNotNull(employee.id); 253 | 254 | List finishedSpans = mockTracer.finishedSpans(); 255 | assertEquals(13, finishedSpans.size()); 256 | 257 | checkSpans(finishedSpans, "hibernate"); 258 | assertNull(mockTracer.activeSpan()); 259 | } 260 | 261 | private void checkSpans(List mockSpans, String dbInstance) { 262 | checkNoEmptyTags(mockSpans); 263 | for (MockSpan mockSpan : mockSpans) { 264 | assertEquals(Tags.SPAN_KIND_CLIENT, mockSpan.tags().get(Tags.SPAN_KIND.getKey())); 265 | assertEquals(JdbcTracingUtils.COMPONENT_NAME, mockSpan.tags().get(Tags.COMPONENT.getKey())); 266 | assertEquals("h2", mockSpan.tags().get(Tags.DB_TYPE.getKey())); 267 | 268 | assertEquals(dbInstance, mockSpan.tags().get(Tags.DB_INSTANCE.getKey())); 269 | assertEquals("localhost:-1", mockSpan.tags().get("peer.address")); 270 | 271 | final String sql = (String) mockSpan.tags().get(Tags.DB_STATEMENT.getKey()); 272 | if (sql != null) { 273 | // empty sql should not be added to avoid NPE in tracers 274 | assertFalse(sql.trim().isEmpty()); 275 | } 276 | assertEquals(0, mockSpan.generatedErrors().size()); 277 | } 278 | } 279 | 280 | private SessionFactory createSessionFactory(boolean traceWithActiveSpanOnly) { 281 | return createSessionFactory(traceWithActiveSpanOnly, new ArrayList()); 282 | } 283 | 284 | private SessionFactory createSessionFactory(boolean traceWithActiveSpanOnly, 285 | List ignored) { 286 | String ignoredForTrace = TestUtil.buildIgnoredString(ignored); 287 | Configuration configuration = new Configuration(); 288 | configuration.addAnnotatedClass(Employee.class); 289 | configuration.setProperty("hibernate.connection.driver_class", 290 | "io.opentracing.contrib.jdbc.TracingDriver"); 291 | configuration.setProperty("hibernate.connection.url", 292 | "jdbc:tracing:h2:mem:hibernate?" + ignoredForTrace + "traceWithActiveSpanOnly=" 293 | + traceWithActiveSpanOnly); 294 | configuration.setProperty("hibernate.connection.username", "sa"); 295 | configuration.setProperty("hibernate.connection.password", ""); 296 | configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); 297 | configuration.setProperty("hibernate.hbm2ddl.auto", "create-drop"); 298 | configuration.setProperty("hibernate.show_sql", "true"); 299 | configuration.setProperty("hibernate.connection.pool_size", "10"); 300 | 301 | StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() 302 | .applySettings(configuration.getProperties()); 303 | return configuration.buildSessionFactory(builder.build()); 304 | } 305 | 306 | 307 | @Entity 308 | @Table(name = "Employee") 309 | private static class Employee { 310 | 311 | @Id 312 | @Column(name = "id") 313 | @GeneratedValue(strategy = GenerationType.AUTO) 314 | private Long id; 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/JdbcTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import static io.opentracing.contrib.jdbc.TestUtil.checkNoEmptyTags; 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | import io.opentracing.mock.MockSpan; 21 | import io.opentracing.mock.MockTracer; 22 | import io.opentracing.tag.Tags; 23 | import io.opentracing.util.GlobalTracerTestUtil; 24 | import java.sql.Connection; 25 | import java.sql.Driver; 26 | import java.sql.DriverManager; 27 | import java.sql.SQLException; 28 | import java.sql.Statement; 29 | import java.util.Enumeration; 30 | import java.util.List; 31 | import org.junit.Before; 32 | import org.junit.BeforeClass; 33 | import org.junit.Test; 34 | 35 | public class JdbcTest { 36 | private static void assertGetDriver(final Connection connection) throws SQLException { 37 | final String originalURL = connection.getMetaData().getURL(); 38 | final Driver driver = getUnderlyingDriver(originalURL); 39 | assertEquals("org.h2.Driver", driver.getClass().getName()); 40 | } 41 | 42 | private static Driver getUnderlyingDriver(final String url) throws SQLException { 43 | final Enumeration enumeration = DriverManager.getDrivers(); 44 | while (enumeration.hasMoreElements()) { 45 | final Driver driver = enumeration.nextElement(); 46 | if (driver.acceptsURL(url) && !(driver instanceof TracingDriver)) { 47 | return driver; 48 | } 49 | } 50 | return null; 51 | } 52 | 53 | private static final MockTracer mockTracer = new MockTracer(); 54 | 55 | @BeforeClass 56 | public static void init() { 57 | GlobalTracerTestUtil.setGlobalTracerUnconditionally(mockTracer); 58 | } 59 | 60 | @Before 61 | public void before() { 62 | mockTracer.reset(); 63 | } 64 | 65 | @Test 66 | public void testPassTracingUrl() throws Exception { 67 | TracingDriver.setInterceptorMode(false); 68 | try (Connection connection = DriverManager.getConnection("jdbc:tracing:h2:mem:jdbc")) { 69 | Statement statement = connection.createStatement(); 70 | statement.executeUpdate("CREATE TABLE employer (id INTEGER)"); 71 | assertGetDriver(connection); 72 | } 73 | 74 | List spans = mockTracer.finishedSpans(); 75 | assertEquals(3, spans.size()); 76 | checkNoEmptyTags(spans); 77 | } 78 | 79 | @Test 80 | public void testFailTracingUrl() throws Exception { 81 | try (Connection connection = DriverManager.getConnection("jdbc:tracing:h2:mem:jdbc")) { 82 | Statement statement = connection.createStatement(); 83 | try { 84 | statement.executeUpdate("CREATE TABLE employer (id INTEGER2)"); 85 | } catch (Exception ignore) { 86 | } 87 | assertGetDriver(connection); 88 | } 89 | 90 | List spans = mockTracer.finishedSpans(); 91 | assertEquals(3, spans.size()); 92 | MockSpan span = spans.get(1); 93 | assertTrue(span.tags().containsKey(Tags.ERROR.getKey())); 94 | checkNoEmptyTags(spans); 95 | } 96 | 97 | @Test 98 | public void testPassOriginalUrl() throws Exception { 99 | TracingDriver.ensureRegisteredAsTheFirstDriver(); 100 | TracingDriver.setInterceptorMode(true); 101 | try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:jdbc")) { 102 | Statement statement = connection.createStatement(); 103 | statement.executeUpdate("CREATE TABLE employer (id INTEGER)"); 104 | assertGetDriver(connection); 105 | } 106 | 107 | List spans = mockTracer.finishedSpans(); 108 | assertEquals(3, spans.size()); 109 | checkNoEmptyTags(spans); 110 | } 111 | 112 | @Test 113 | public void testFailOriginalUrl() throws Exception { 114 | TracingDriver.ensureRegisteredAsTheFirstDriver(); 115 | TracingDriver.setInterceptorMode(true); 116 | try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:jdbc")) { 117 | Statement statement = connection.createStatement(); 118 | try { 119 | statement.executeUpdate("CREATE TABLE employer (id INTEGER2)"); 120 | } catch (Exception ignore) { 121 | } 122 | assertGetDriver(connection); 123 | } 124 | 125 | List spans = mockTracer.finishedSpans(); 126 | assertEquals(3, spans.size()); 127 | MockSpan span = spans.get(1); 128 | assertTrue(span.tags().containsKey(Tags.ERROR.getKey())); 129 | checkNoEmptyTags(spans); 130 | } 131 | 132 | @Test 133 | public void testFailInterceptor() throws Exception { 134 | TracingDriver.setInterceptorMode(false); 135 | try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:jdbc")) { 136 | Statement statement = connection.createStatement(); 137 | try { 138 | statement.executeUpdate("CREATE TABLE employer (id INTEGER2)"); 139 | } catch (Exception ignore) { 140 | } 141 | assertGetDriver(connection); 142 | } 143 | 144 | List spans = mockTracer.finishedSpans(); 145 | assertEquals(0, spans.size()); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/JdbcTracingUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import static io.opentracing.contrib.jdbc.TestUtil.checkNoEmptyTags; 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | import io.opentracing.mock.MockSpan; 21 | import io.opentracing.mock.MockTracer; 22 | import io.opentracing.util.GlobalTracerTestUtil; 23 | import java.sql.Connection; 24 | import java.sql.DriverManager; 25 | import java.sql.Statement; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import org.junit.AfterClass; 29 | import org.junit.Before; 30 | import org.junit.BeforeClass; 31 | import org.junit.Test; 32 | 33 | public class JdbcTracingUtilsTest { 34 | 35 | private static final MockTracer mockTracer = new MockTracer(); 36 | 37 | @BeforeClass 38 | public static void init() { 39 | GlobalTracerTestUtil.setGlobalTracerUnconditionally(mockTracer); 40 | } 41 | 42 | @Before 43 | public void before() { 44 | mockTracer.reset(); 45 | JdbcTracing.setSlowQueryThresholdMs(0); 46 | } 47 | 48 | @AfterClass 49 | public static void afterClass() { 50 | TracingDriver.setTraceEnabled(true); 51 | JdbcTracing.setSlowQueryThresholdMs(0); 52 | } 53 | 54 | @Test 55 | public void buildSpanWithTracedEnabled() throws Exception { 56 | TracingDriver.setInterceptorMode(false); 57 | TracingDriver.setTraceEnabled(true); 58 | try (Connection connection = DriverManager.getConnection("jdbc:tracing:h2:mem:jdbc")) { 59 | Statement statement = connection.createStatement(); 60 | statement.executeUpdate("CREATE TABLE employer (id INTEGER)"); 61 | } 62 | 63 | List spans = mockTracer.finishedSpans(); 64 | assertEquals(3, spans.size()); 65 | checkNoEmptyTags(spans); 66 | } 67 | 68 | @Test 69 | public void buildSpanWithoutTraceEnabled() throws Exception { 70 | TracingDriver.setInterceptorMode(false); 71 | TracingDriver.setTraceEnabled(false); 72 | try (Connection connection = DriverManager.getConnection("jdbc:tracing:h2:mem:jdbc")) { 73 | Statement statement = connection.createStatement(); 74 | statement.executeUpdate("CREATE TABLE employer (id INTEGER)"); 75 | } 76 | 77 | assertTrue(mockTracer.finishedSpans().isEmpty()); 78 | } 79 | 80 | @Test 81 | public void setSlowTagCorrectly() throws Exception { 82 | final int slowQueryThresholdMs = 100; 83 | JdbcTracing.setSlowQueryThresholdMs(slowQueryThresholdMs); 84 | 85 | JdbcTracingUtils.execute( 86 | "SlowQuery", 87 | () -> Thread.sleep(slowQueryThresholdMs * 2), 88 | null, 89 | ConnectionInfo.UNKNOWN_CONNECTION_INFO, 90 | false, 91 | Collections.emptySet(), 92 | mockTracer); 93 | 94 | final List finishedSpans = mockTracer.finishedSpans(); 95 | assertEquals("Should have traced a query execution", 1, finishedSpans.size()); 96 | final MockSpan slowQuerySpan = finishedSpans.get(0); 97 | assertTrue("Span should be tagged slow", 98 | slowQuerySpan.tags().containsKey(JdbcTracingUtils.SLOW.getKey())); 99 | } 100 | 101 | @Test 102 | public void setExcludeFastTagCorrectly() throws Exception { 103 | final int excludeFastQueryThresholdMs = 100; 104 | JdbcTracing.setExcludeFastQueryThresholdMs(excludeFastQueryThresholdMs); 105 | 106 | JdbcTracingUtils.execute( 107 | "FastQuery", 108 | () -> Thread.sleep(excludeFastQueryThresholdMs / 2), 109 | null, 110 | ConnectionInfo.UNKNOWN_CONNECTION_INFO, 111 | false, 112 | Collections.emptySet(), 113 | mockTracer); 114 | 115 | final List finishedSpans = mockTracer.finishedSpans(); 116 | assertEquals("Should have traced a query execution", 1, finishedSpans.size()); 117 | final MockSpan fastQuerySpan = finishedSpans.get(0); 118 | assertTrue("Span should be tagged with sampling.priority=0", 119 | fastQuerySpan.tags().containsKey(JdbcTracingUtils.SAMPLING_PRIORITY.getKey())); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/SpringTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import static io.opentracing.contrib.jdbc.TestUtil.checkNoEmptyTags; 18 | import static io.opentracing.contrib.jdbc.TestUtil.checkSameTrace; 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertNull; 22 | 23 | import io.opentracing.Scope; 24 | import io.opentracing.mock.MockSpan; 25 | import io.opentracing.mock.MockTracer; 26 | import io.opentracing.tag.Tags; 27 | import io.opentracing.util.GlobalTracerTestUtil; 28 | import java.sql.PreparedStatement; 29 | import java.sql.SQLException; 30 | import java.util.ArrayList; 31 | import java.util.Arrays; 32 | import java.util.List; 33 | import org.apache.commons.dbcp2.BasicDataSource; 34 | import org.junit.Before; 35 | import org.junit.BeforeClass; 36 | import org.junit.Test; 37 | import org.springframework.jdbc.core.BatchPreparedStatementSetter; 38 | import org.springframework.jdbc.core.JdbcTemplate; 39 | 40 | public class SpringTest { 41 | 42 | private static final MockTracer mockTracer = new MockTracer(); 43 | 44 | private final int DB_CONNECTION_SPAN_COUNT = 2; 45 | 46 | @BeforeClass 47 | public static void init() { 48 | GlobalTracerTestUtil.setGlobalTracerUnconditionally(mockTracer); 49 | } 50 | 51 | @Before 52 | public void before() { 53 | mockTracer.reset(); 54 | } 55 | 56 | @Test 57 | public void batch() throws SQLException { 58 | BasicDataSource dataSource = getDataSource(false); 59 | 60 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 61 | jdbcTemplate.execute("CREATE TABLE batch (id INTEGER)"); 62 | 63 | final List ids = Arrays.asList(1, 2, 3, 4, 5); 64 | jdbcTemplate.batchUpdate("INSERT INTO batch (id) VALUES (?)", 65 | new BatchPreparedStatementSetter() { 66 | @Override 67 | public void setValues(PreparedStatement preparedStatement, int i) throws SQLException { 68 | preparedStatement.setInt(1, ids.get(i)); 69 | } 70 | 71 | @Override 72 | public int getBatchSize() { 73 | return ids.size(); 74 | } 75 | } 76 | ); 77 | 78 | dataSource.close(); 79 | 80 | List spans = mockTracer.finishedSpans(); 81 | assertEquals(DB_CONNECTION_SPAN_COUNT + 4, spans.size()); 82 | 83 | for (MockSpan span : spans.subList(DB_CONNECTION_SPAN_COUNT + 2, spans.size() - 1)) { 84 | assertEquals(Tags.SPAN_KIND_CLIENT, span.tags().get(Tags.SPAN_KIND.getKey())); 85 | assertEquals(JdbcTracingUtils.COMPONENT_NAME, span.tags().get(Tags.COMPONENT.getKey())); 86 | assertThat(span.tags().get(Tags.DB_STATEMENT.getKey()).toString()).isNotEmpty(); 87 | assertEquals("h2", span.tags().get(Tags.DB_TYPE.getKey())); 88 | assertEquals("spring", span.tags().get(Tags.DB_INSTANCE.getKey())); 89 | assertEquals("localhost:-1", span.tags().get("peer.address")); 90 | assertEquals(0, span.generatedErrors().size()); 91 | } 92 | 93 | assertNull(mockTracer.activeSpan()); 94 | checkNoEmptyTags(spans); 95 | } 96 | 97 | @Test 98 | public void spring() throws SQLException { 99 | BasicDataSource dataSource = getDataSource(false); 100 | 101 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 102 | jdbcTemplate.execute("CREATE TABLE employee (id INTEGER)"); 103 | 104 | dataSource.close(); 105 | 106 | List finishedSpans = mockTracer.finishedSpans(); 107 | assertEquals(DB_CONNECTION_SPAN_COUNT + 3, finishedSpans.size()); 108 | MockSpan mockSpan = finishedSpans.get(DB_CONNECTION_SPAN_COUNT + 1); 109 | 110 | assertEquals(Tags.SPAN_KIND_CLIENT, mockSpan.tags().get(Tags.SPAN_KIND.getKey())); 111 | assertEquals(JdbcTracingUtils.COMPONENT_NAME, mockSpan.tags().get(Tags.COMPONENT.getKey())); 112 | assertThat(mockSpan.tags().get(Tags.DB_STATEMENT.getKey()).toString()).isNotEmpty(); 113 | assertEquals("h2", mockSpan.tags().get(Tags.DB_TYPE.getKey())); 114 | assertEquals("spring", mockSpan.tags().get(Tags.DB_INSTANCE.getKey())); 115 | assertEquals("localhost:-1", mockSpan.tags().get("peer.address")); 116 | 117 | assertEquals(0, mockSpan.generatedErrors().size()); 118 | 119 | assertNull(mockTracer.activeSpan()); 120 | checkNoEmptyTags(finishedSpans); 121 | } 122 | 123 | @Test 124 | public void spring_active_span_only() throws Exception { 125 | BasicDataSource dataSource = getDataSource(true); 126 | 127 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 128 | jdbcTemplate.execute("CREATE TABLE skip_new_spans (id INTEGER)"); 129 | 130 | dataSource.close(); 131 | 132 | List finishedSpans = mockTracer.finishedSpans(); 133 | assertEquals(0, finishedSpans.size()); 134 | checkNoEmptyTags(finishedSpans); 135 | } 136 | 137 | @Test 138 | public void spring_with_parent() throws Exception { 139 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 140 | try (Scope ignored = mockTracer.activateSpan(parent)) { 141 | BasicDataSource dataSource = getDataSource(false); 142 | 143 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 144 | jdbcTemplate.execute("CREATE TABLE with_parent_1 (id INTEGER)"); 145 | jdbcTemplate.execute("CREATE TABLE with_parent_2 (id INTEGER)"); 146 | 147 | dataSource.close(); 148 | } 149 | parent.finish(); 150 | 151 | List spans = mockTracer.finishedSpans(); 152 | assertEquals(DB_CONNECTION_SPAN_COUNT + 5, spans.size()); 153 | 154 | checkSameTrace(spans); 155 | checkNoEmptyTags(spans); 156 | } 157 | 158 | @Test 159 | public void spring_with_parent_and_active_span_only() throws Exception { 160 | final MockSpan parent = mockTracer.buildSpan("parent").start(); 161 | try (Scope ignored = mockTracer.activateSpan(parent)) { 162 | BasicDataSource dataSource = getDataSource(true); 163 | 164 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 165 | jdbcTemplate.execute("CREATE TABLE with_parent_skip_1 (id INTEGER)"); 166 | jdbcTemplate.execute("CREATE TABLE with_parent_skip_2 (id INTEGER)"); 167 | 168 | dataSource.close(); 169 | } 170 | parent.finish(); 171 | 172 | List spans = mockTracer.finishedSpans(); 173 | assertEquals(DB_CONNECTION_SPAN_COUNT + 5, spans.size()); 174 | 175 | checkSameTrace(spans); 176 | checkNoEmptyTags(spans); 177 | } 178 | 179 | @Test 180 | public void spring_with_ignored_statement() throws Exception { 181 | BasicDataSource dataSource = getDataSource(false, Arrays.asList( 182 | "CREATE TABLE ignored (id INTEGER, TEST VARCHAR)", 183 | "INSERT INTO ignored (id, \\\"TEST\\\") VALUES (1, 'value')" 184 | )); 185 | 186 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 187 | jdbcTemplate.execute("CREATE TABLE ignored (id INTEGER, TEST VARCHAR)"); 188 | jdbcTemplate.execute("INSERT INTO ignored (id, \"TEST\") VALUES (1, 'value')"); 189 | jdbcTemplate.execute("CREATE TABLE not_ignored (id INTEGER)"); 190 | 191 | dataSource.close(); 192 | 193 | List finishedSpans = mockTracer.finishedSpans(); 194 | assertEquals(DB_CONNECTION_SPAN_COUNT + 3, finishedSpans.size()); 195 | checkNoEmptyTags(finishedSpans); 196 | } 197 | 198 | private static BasicDataSource getDataSource(boolean traceWithActiveSpanOnly) { 199 | return getDataSource(traceWithActiveSpanOnly, new ArrayList()); 200 | } 201 | 202 | private static BasicDataSource getDataSource(boolean traceWithActiveSpanOnly, 203 | List ignored) { 204 | 205 | String ignoreForTracing = TestUtil.buildIgnoredString(ignored); 206 | 207 | BasicDataSource dataSource = new BasicDataSource(); 208 | dataSource 209 | .setUrl("jdbc:tracing:h2:mem:spring?" + ignoreForTracing + 210 | "traceWithActiveSpanOnly=" + traceWithActiveSpanOnly); 211 | dataSource.setUsername("sa"); 212 | dataSource.setPassword(""); 213 | return dataSource; 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/TestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertNotNull; 19 | 20 | import io.opentracing.mock.MockSpan; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.Map.Entry; 24 | 25 | class TestUtil { 26 | 27 | static void checkSameTrace(List spans) { 28 | for (int i = 0; i < spans.size() - 1; i++) { 29 | assertEquals(spans.get(i).context().traceId(), spans.get(i + 1).context().traceId()); 30 | assertEquals(spans.get(spans.size() - 1).context().spanId(), spans.get(i).parentId()); 31 | } 32 | } 33 | 34 | static void checkNoEmptyTags(List spans) { 35 | for (MockSpan span : spans) { 36 | for (Entry entry : span.tags().entrySet()) { 37 | assertNotNull(entry.getValue()); 38 | if (entry.getValue() instanceof String) { 39 | String tagValue = (String) entry.getValue(); 40 | assertFalse(tagValue.trim().isEmpty()); 41 | } 42 | } 43 | } 44 | } 45 | 46 | static String buildIgnoredString(Collection ignored) { 47 | StringBuilder ignoreForTracing = new StringBuilder(); 48 | for (String query : ignored) { 49 | ignoreForTracing.append("ignoreForTracing=\""); 50 | ignoreForTracing.append(query.replaceAll("\"", "\\\"")); 51 | ignoreForTracing.append("\";"); 52 | } 53 | return ignoreForTracing.toString(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/TracingDataSourceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertNull; 19 | import static org.junit.Assert.assertTrue; 20 | 21 | import io.opentracing.mock.MockSpan; 22 | import io.opentracing.mock.MockTracer; 23 | import io.opentracing.tag.Tags; 24 | import java.sql.Connection; 25 | import java.sql.SQLException; 26 | import org.apache.commons.dbcp2.BasicDataSource; 27 | import org.junit.Test; 28 | 29 | public class TracingDataSourceTest { 30 | @Test 31 | public void traces_acquiring_connection() throws Exception { 32 | final BasicDataSource dataSource = getDataSource(); 33 | final MockTracer mockTracer = new MockTracer(); 34 | try (final TracingDataSource tracingDataSource = new TracingDataSource(mockTracer, 35 | dataSource)) { 36 | try (final Connection connection = tracingDataSource.getConnection()) { 37 | assertFalse(mockTracer.finishedSpans().isEmpty()); 38 | } 39 | } 40 | } 41 | 42 | @Test 43 | public void sets_error() throws Exception { 44 | final BasicDataSource dataSource = getErroneousDataSource(); 45 | final MockTracer mockTracer = new MockTracer(); 46 | try (final TracingDataSource tracingDataSource = new TracingDataSource(mockTracer, 47 | dataSource)) { 48 | try (final Connection connection = tracingDataSource.getConnection()) { 49 | assertNull("Get connection", connection); 50 | } catch (SQLException ignored) { 51 | } 52 | } 53 | 54 | assertFalse(mockTracer.finishedSpans().isEmpty()); 55 | MockSpan finishedSpan = mockTracer.finishedSpans().get(0); 56 | assertTrue("Span contains error tag", finishedSpan.tags().containsKey(Tags.ERROR.getKey())); 57 | } 58 | 59 | @Test(expected = SQLException.class) 60 | public void rethrows_any_error() throws Exception { 61 | final BasicDataSource dataSource = getErroneousDataSource(); 62 | final MockTracer mockTracer = new MockTracer(); 63 | try (final TracingDataSource tracingDataSource = new TracingDataSource(mockTracer, 64 | dataSource)) { 65 | tracingDataSource.getConnection(); 66 | } 67 | } 68 | 69 | @Test 70 | public void detect_connection_info() throws Exception { 71 | final BasicDataSource dataSource = getDataSource(); 72 | final MockTracer mockTracer = new MockTracer(); 73 | try (final TracingDataSource tracingDataSource = new TracingDataSource(mockTracer, 74 | dataSource)) { 75 | tracingDataSource.getConnection(); 76 | } 77 | assertFalse(mockTracer.finishedSpans().isEmpty()); 78 | MockSpan finishedSpan = mockTracer.finishedSpans().get(0); 79 | assertEquals("Span contains tag db.type=h2", "h2", 80 | finishedSpan.tags().get(Tags.DB_TYPE.getKey())); 81 | } 82 | 83 | private static BasicDataSource getDataSource() { 84 | BasicDataSource dataSource = new BasicDataSource(); 85 | dataSource.setUrl("jdbc:h2:mem:dataSourceTest"); 86 | return dataSource; 87 | } 88 | 89 | private static BasicDataSource getErroneousDataSource() { 90 | BasicDataSource dataSource = new BasicDataSource(); 91 | dataSource.setUrl("jdbc:invalid"); 92 | return dataSource; 93 | } 94 | } -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/TracingDriverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc; 15 | 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.assertNotNull; 19 | 20 | import io.opentracing.Tracer; 21 | import io.opentracing.mock.MockTracer; 22 | import io.opentracing.util.GlobalTracer; 23 | import io.opentracing.util.GlobalTracerTestUtil; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | public class TracingDriverTest { 28 | 29 | @Before 30 | public void before() { 31 | GlobalTracerTestUtil.resetGlobalTracer(); 32 | } 33 | 34 | @Test 35 | public void testGlobalTracer() { 36 | TracingDriver tracingDriver = new TracingDriver(); 37 | assertNotNull(tracingDriver.getTracer()); 38 | } 39 | 40 | @Test 41 | public void testExplicitTracer() { 42 | Tracer tracer = new MockTracer(); 43 | GlobalTracer.registerIfAbsent(tracer); 44 | Tracer tracer2 = new MockTracer(); 45 | TracingDriver tracingDriver = new TracingDriver(); 46 | tracingDriver.setTracer(tracer2); 47 | assertEquals(tracer2, tracingDriver.getTracer()); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/parser/AS400URLParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import static org.hamcrest.CoreMatchers.equalTo; 17 | import static org.hamcrest.CoreMatchers.is; 18 | import static org.hamcrest.CoreMatchers.not; 19 | import static org.hamcrest.MatcherAssert.assertThat; 20 | 21 | import io.opentracing.contrib.jdbc.ConnectionInfo; 22 | import org.junit.Test; 23 | 24 | /** 25 | * Test for {@link AS400URLParser} 26 | * 27 | * @author Capgemini 28 | */ 29 | public class AS400URLParserTest { 30 | 31 | @Test 32 | public void testMatchShort() { 33 | String url = "jdbc:as400://myhost"; 34 | ConnectionInfo connectionInfo = URLParser.parse(url); 35 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 36 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost"))); 37 | assertThat(connectionInfo.getDbInstance(), 38 | is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance()))); 39 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 40 | } 41 | 42 | @Test 43 | public void testMatchShortWithSlash() { 44 | String url = "jdbc:as400://myhost/"; 45 | ConnectionInfo connectionInfo = URLParser.parse(url); 46 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 47 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost"))); 48 | assertThat(connectionInfo.getDbInstance(), 49 | is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance()))); 50 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 51 | } 52 | 53 | @Test 54 | public void testMatchShortWithSlashAnsOptions() { 55 | String url = "jdbc:as400://myhost/;naming=sql;errors=full"; 56 | ConnectionInfo connectionInfo = URLParser.parse(url); 57 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 58 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost"))); 59 | assertThat(connectionInfo.getDbInstance(), 60 | is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance()))); 61 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 62 | } 63 | 64 | 65 | @Test 66 | public void testWithOptions() { 67 | String url = "jdbc:as400://myhost.mydomain.com;naming=sql;errors=full"; 68 | ConnectionInfo connectionInfo = URLParser.parse(url); 69 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 70 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com"))); 71 | assertThat(connectionInfo.getDbInstance(), 72 | is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO.getDbInstance()))); 73 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 74 | } 75 | 76 | @Test 77 | public void testFull() { 78 | String url = "jdbc:as400://myhost.mydomain.com/myinstance;naming=sql;errors=full"; 79 | ConnectionInfo connectionInfo = URLParser.parse(url); 80 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 81 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com"))); 82 | assertThat(connectionInfo.getDbInstance(), is(equalTo("myinstance"))); 83 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 84 | } 85 | 86 | @Test 87 | public void testFullWithSlash() { 88 | String url = "jdbc:as400://myhost.mydomain.com/myinstance/;naming=sql;errors=full"; 89 | ConnectionInfo connectionInfo = URLParser.parse(url); 90 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 91 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com"))); 92 | assertThat(connectionInfo.getDbInstance(), is(equalTo("myinstance"))); 93 | assertThat(connectionInfo.getDbType(), is(equalTo("as400"))); 94 | } 95 | 96 | 97 | @Test 98 | public void testNotMatch() { 99 | String url = "jdbc:as400:notmatching"; 100 | ConnectionInfo connectionInfo = URLParser.parse(url); 101 | assertThat(connectionInfo, is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO))); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/parser/DB2URLParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import static org.hamcrest.CoreMatchers.equalTo; 17 | import static org.hamcrest.CoreMatchers.is; 18 | import static org.hamcrest.CoreMatchers.not; 19 | import static org.hamcrest.MatcherAssert.assertThat; 20 | 21 | import io.opentracing.contrib.jdbc.ConnectionInfo; 22 | import org.junit.Test; 23 | 24 | /** 25 | * Test for {@link DB2URLParser} 26 | * 27 | * @author oburgosm 28 | * @since 0.2.12 29 | */ 30 | public class DB2URLParserTest { 31 | 32 | @Test 33 | public void testMatchFull() { 34 | String url = "jdbc:db2://myhost.mydomain.com:50000/MYINSTANCE:retrieveMessagesFromServerOnGetMessage=true;useIdentityValLocalForAutoGeneratedKeys=true;"; 35 | ConnectionInfo connectionInfo = URLParser.parse(url); 36 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 37 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com:50000"))); 38 | assertThat(connectionInfo.getDbInstance(), is(equalTo("MYINSTANCE"))); 39 | assertThat(connectionInfo.getDbType(), is(equalTo("db2"))); 40 | } 41 | 42 | @Test 43 | public void testMatchWithoutOptions() { 44 | String url = "jdbc:db2://myhost.mydomain.com:50000/MYINSTANCE"; 45 | ConnectionInfo connectionInfo = URLParser.parse(url); 46 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 47 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com:50000"))); 48 | assertThat(connectionInfo.getDbInstance(), is(equalTo("MYINSTANCE"))); 49 | assertThat(connectionInfo.getDbType(), is(equalTo("db2"))); 50 | } 51 | 52 | @Test 53 | public void testMatchWithoutPort() { 54 | String url = "jdbc:db2://myhost.mydomain.com/MYINSTANCE"; 55 | ConnectionInfo connectionInfo = URLParser.parse(url); 56 | assertThat(connectionInfo, is(not(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO)))); 57 | assertThat(connectionInfo.getDbPeer(), is(equalTo("myhost.mydomain.com"))); 58 | assertThat(connectionInfo.getDbInstance(), is(equalTo("MYINSTANCE"))); 59 | assertThat(connectionInfo.getDbType(), is(equalTo("db2"))); 60 | } 61 | 62 | @Test 63 | public void testNotMatch() { 64 | String url = "jdbc:db2:notmatching"; 65 | ConnectionInfo connectionInfo = URLParser.parse(url); 66 | assertThat(connectionInfo, is(equalTo(ConnectionInfo.UNKNOWN_CONNECTION_INFO))); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/parser/OracleURLParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import java.util.stream.Stream; 17 | 18 | import io.opentracing.contrib.jdbc.ConnectionInfo; 19 | import org.junit.jupiter.params.ParameterizedTest; 20 | import org.junit.jupiter.params.provider.Arguments; 21 | import org.junit.jupiter.params.provider.MethodSource; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | 25 | class OracleURLParserTest { 26 | private static final String ORACLE = "oracle"; 27 | private final OracleURLParser testee = new OracleURLParser(); 28 | 29 | private static Stream easyConnectUrls() { 30 | return Stream.of( // 31 | Arguments 32 | .of("jdbc:oracle:thin:@192.168.105.100", "192.168.105.100:1521", "192.168.105.100"), // 33 | Arguments.of("jdbc:oracle:thin:@192.168.105.100:1234", "192.168.105.100:1234", 34 | "192.168.105.100"), // 35 | Arguments.of("jdbc:oracle:thin:@localhost/XEPDB1", "localhost:1521", "XEPDB1"), // 36 | Arguments.of("jdbc:oracle:thin:@localhost:1234/XEPDB1", "localhost:1234", "XEPDB1"), // 37 | Arguments.of("jdbc:oracle:thin:@//localhost:1234/XEPDB1", "localhost:1234", "XEPDB1"), // 38 | Arguments.of("jdbc:oracle:thin:@//localhost:1234/XEPDB1:server/instance", "localhost:1234", 39 | "XEPDB1"), // 40 | Arguments.of("jdbc:oracle:oci:@//localhost:1234/XEPDB1:server/instance", "localhost:1234", 41 | "XEPDB1"), // 42 | Arguments 43 | .of("jdbc:oracle:thin:@ldap://localhost:1234/XEPDB1,cn=OracleContext,dc=myco,dc=com", 44 | "localhost:1234", "XEPDB1,cn=OracleContext,dc=myco,dc=com") // 45 | ); 46 | } 47 | 48 | private static Stream tnsNameUrls() { 49 | return Stream.of( // 50 | Arguments 51 | .of("jdbc:Oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))", 52 | "localhost:1521", "orcl"), // 53 | Arguments 54 | .of("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= localhost )(PORT= 1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))", 55 | "localhost:1521", "orcl"), // 56 | Arguments 57 | .of("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL= TCP)(HOST=hostA)(PORT= 1523 ))(ADDRESS=(PROTOCOL=TCP)(HOST=hostB)(PORT= 1521 )))(SOURCE_ROUTE=yes)(CONNECT_DATA=(SERVICE_NAME=orcl)))", 58 | "hostA:1523,hostB:1521", "orcl"), // 59 | Arguments 60 | .of("jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL= TCP)(HOST=hostA)(PORT= 1523 ))(ADDRESS=(PROTOCOL=TCP)(HOST=hostB)(PORT= 1521 )))(SOURCE_ROUTE=yes)(CONNECT_DATA=(SERVICE_NAME=orcl)))", 61 | "hostA:1523,hostB:1521", "orcl") // 62 | ); 63 | } 64 | 65 | private static Stream otherUrls() { 66 | return Stream.of( // 67 | Arguments.of("jdbc:Oracle:thin:@localhost:orcl", "localhost:1521", "orcl"), // 68 | Arguments.of("jdbc:oracle:thin:@localhost:orcl", "localhost:1521", "orcl"), // 69 | Arguments.of("jdbc:oracle:thin:@localhost:1522:orcl", "localhost:1522", "orcl"), // 70 | Arguments.of("jdbc:oracle:thin:@//localhost:1521/orcl", "localhost:1521", "orcl"), // 71 | Arguments.of("jdbc:oracle:thin:scott/tiger@myhost:1521:orcl", "myhost:1521", "orcl"), // 72 | Arguments.of("jdbc:oracle:thin:@orcl", "orcl:1521", "orcl"), // 73 | Arguments.of("jdbc:oracle:oci:@orcl", "orcl:1521", "orcl"), // 74 | Arguments.of("jdbc:Oracle:oci:@orcl", "orcl:1521", "orcl"), // 75 | Arguments.of("jdbc:oracle:thin:@ldap://localhost/orcl,cn=OracleContext,dc=myco,dc=com", 76 | "localhost:1521", "orcl,cn=OracleContext,dc=myco,dc=com"), // 77 | Arguments.of("jdbc:Oracle:thin:@ldap://localhost/orcl,cn=OracleContext,dc=myco,dc=com", 78 | "localhost:1521", "orcl,cn=OracleContext,dc=myco,dc=com") // 79 | ); 80 | } 81 | 82 | @ParameterizedTest(name = "[{0}]") 83 | @MethodSource("easyConnectUrls") 84 | void parseEasyConnect(final String url, final String dbPeer, final String dbInstance) { 85 | final ConnectionInfo result = testee.parse(url); 86 | assertThat(result.getDbType()).isEqualTo(ORACLE); 87 | assertThat(result.getDbPeer()).isEqualTo(dbPeer); 88 | assertThat(result.getDbInstance()).isEqualTo(dbInstance); 89 | } 90 | 91 | @ParameterizedTest(name = "[{0}]") 92 | @MethodSource("tnsNameUrls") 93 | void parseTnsName(final String url, final String dbPeer, final String dbInstance) { 94 | final ConnectionInfo result = testee.parse(url); 95 | assertThat(result.getDbType()).isEqualTo(ORACLE); 96 | assertThat(result.getDbPeer()).isEqualTo(dbPeer); 97 | assertThat(result.getDbInstance()).isEqualTo(dbInstance); 98 | } 99 | 100 | @ParameterizedTest(name = "[{0}]") 101 | @MethodSource("otherUrls") 102 | void parseOther(final String url, final String dbPeer, final String dbInstance) { 103 | final ConnectionInfo result = testee.parse(url); 104 | assertThat(result).isNotNull(); 105 | assertThat(result.getDbType()).isEqualTo(ORACLE); 106 | assertThat(result.getDbPeer()).isEqualTo(dbPeer); 107 | assertThat(result.getDbInstance()).isEqualTo(dbInstance); 108 | } 109 | } -------------------------------------------------------------------------------- /src/test/java/io/opentracing/contrib/jdbc/parser/SqlServerURLParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.jdbc.parser; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | import io.opentracing.contrib.jdbc.ConnectionInfo; 19 | import java.util.stream.Stream; 20 | import org.junit.jupiter.params.ParameterizedTest; 21 | import org.junit.jupiter.params.provider.Arguments; 22 | import org.junit.jupiter.params.provider.MethodSource; 23 | 24 | class SqlServerURLParserTest { 25 | private static final String SQLSERVER = "sqlserver"; 26 | private final SqlServerURLParser urlParser = new SqlServerURLParser(); 27 | 28 | private static Stream connectUrls() { 29 | return Stream.of( 30 | Arguments.of("jdbc:sqlserver://localhost\\instanceName:1435", "localhost:1435", null), 31 | Arguments.of("jdbc:sqlserver://localhost;integratedSecurity=true;", "localhost:1433", null), 32 | Arguments 33 | .of("jdbc:sqlserver://localhost;databaseName=AdventureWorks;integratedSecurity=true;", 34 | "localhost:1433", "AdventureWorks"), 35 | Arguments 36 | .of("jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks;integratedSecurity=true;", 37 | "localhost:1433", "AdventureWorks"), 38 | Arguments 39 | .of("jdbc:sqlserver://localhost;databaseName=AdventureWorks;integratedSecurity=true;applicationName=MyApp;", 40 | "localhost:1433", "AdventureWorks") 41 | ); 42 | } 43 | 44 | @ParameterizedTest(name = "[{0}]") 45 | @MethodSource("connectUrls") 46 | void parseConnectUrls(final String url, final String dbPeer, final String dbInstance) { 47 | final ConnectionInfo result = urlParser.parse(url); 48 | assertThat(result.getDbType()).isEqualTo(SQLSERVER); 49 | assertThat(result.getDbPeer()).isEqualTo(dbPeer); 50 | assertThat(result.getDbInstance()).isEqualTo(dbInstance); 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 16 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /travis/publish.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2017-2021 The OpenTracing Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # or implied. See the License for the specific language governing permissions and limitations under 12 | # the License. 13 | # 14 | 15 | set -euo pipefail 16 | set -x 17 | 18 | build_started_by_tag() { 19 | if [ "${TRAVIS_TAG}" == "" ]; then 20 | echo "[Publishing] This build was not started by a tag, publishing snapshot" 21 | return 1 22 | else 23 | echo "[Publishing] This build was started by the tag ${TRAVIS_TAG}, publishing release" 24 | return 0 25 | fi 26 | } 27 | 28 | is_pull_request() { 29 | if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then 30 | echo "[Not Publishing] This is a Pull Request" 31 | return 0 32 | else 33 | echo "[Publishing] This is not a Pull Request" 34 | return 1 35 | fi 36 | } 37 | 38 | is_travis_branch_master() { 39 | if [ "${TRAVIS_BRANCH}" = master ]; then 40 | echo "[Publishing] Travis branch is master" 41 | return 0 42 | else 43 | echo "[Not Publishing] Travis branch is not master" 44 | return 1 45 | fi 46 | } 47 | 48 | check_travis_branch_equals_travis_tag() { 49 | #Weird comparison comparing branch to tag because when you 'git push --tags' 50 | #the branch somehow becomes the tag value 51 | #github issue: https://github.com/travis-ci/travis-ci/issues/1675 52 | if [ "${TRAVIS_BRANCH}" != "${TRAVIS_TAG}" ]; then 53 | echo "Travis branch does not equal Travis tag, which it should, bailing out." 54 | echo " github issue: https://github.com/travis-ci/travis-ci/issues/1675" 55 | exit 1 56 | else 57 | echo "[Publishing] Branch (${TRAVIS_BRANCH}) same as Tag (${TRAVIS_TAG})" 58 | fi 59 | } 60 | 61 | check_release_tag() { 62 | tag="${TRAVIS_TAG}" 63 | if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]]; then 64 | echo "Build started by version tag $tag. During the release process tags like this" 65 | echo "are created by the 'release' Maven plugin. Nothing to do here." 66 | exit 0 67 | elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]]; then 68 | echo "You must specify a tag of the format 'release-0.0.0' to release this project." 69 | echo "The provided tag ${tag} doesn't match that. Aborting." 70 | exit 1 71 | fi 72 | } 73 | 74 | is_release_commit() { 75 | project_version=$(./mvnw help:evaluate -N -Dexpression=project.version | grep -v '\[') 76 | if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]]; then 77 | echo "Build started by release commit $project_version. Will synchronize to maven central." 78 | return 0 79 | else 80 | return 1 81 | fi 82 | } 83 | 84 | release_version() { 85 | echo "${TRAVIS_TAG}" | sed 's/^release-//' 86 | } 87 | 88 | safe_checkout_master() { 89 | # We need to be on a branch for release:perform to be able to create commits, and we want that branch to be master. 90 | # But we also want to make sure that we build and release exactly the tagged version, so we verify that the remote 91 | # master is where our tag is. 92 | git checkout -B master 93 | git fetch origin master:origin/master 94 | commit_local_master="$(git show --pretty='format:%H' master)" 95 | commit_remote_master="$(git show --pretty='format:%H' origin/master)" 96 | if [ "$commit_local_master" != "$commit_remote_master" ]; then 97 | echo "Master on remote 'origin' has commits since the version under release, aborting" 98 | exit 1 99 | fi 100 | } 101 | 102 | #---------------------- 103 | # MAIN 104 | #---------------------- 105 | 106 | if ! is_pull_request && build_started_by_tag; then 107 | check_travis_branch_equals_travis_tag 108 | check_release_tag 109 | fi 110 | 111 | ./mvnw install -nsu 112 | 113 | # If we are on a pull request, our only job is to run tests, which happened above via ./mvnw install 114 | if is_pull_request; then 115 | true 116 | # If we are on master, we will deploy the latest snapshot or release version 117 | # - If a release commit fails to deploy for a transient reason, delete the broken version from bintray and click rebuild 118 | elif is_travis_branch_master; then 119 | ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DskipTests deploy 120 | 121 | # If the deployment succeeded, sync it to Maven Central. Note: this needs to be done once per project, not module, hence -N 122 | if is_release_commit; then 123 | ./mvnw --batch-mode -s ./.settings.xml -nsu -N io.zipkin.centralsync-maven-plugin:centralsync-maven-plugin:sync 124 | fi 125 | 126 | # If we are on a release tag, the following will update any version references and push a version tag for deployment. 127 | elif build_started_by_tag; then 128 | safe_checkout_master 129 | ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DreleaseVersion="$(release_version)" -Darguments="-DskipTests" release:prepare 130 | fi 131 | --------------------------------------------------------------------------------