├── .editorconfig ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── config.yml │ └── feature.md └── workflows │ ├── create_release.yml │ ├── deploy.yml │ └── test.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .settings.xml ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── build-bin ├── README.md ├── configure_deploy ├── configure_test ├── deploy ├── docker │ └── configure_docker ├── git │ ├── login_git │ └── version_from_trigger_tag ├── gpg │ └── configure_gpg ├── maven │ ├── maven_deploy │ ├── maven_go_offline │ ├── maven_opts │ └── maven_release └── test ├── docker-compose.yml ├── docker └── kafka-connector │ ├── jdbc-sink.json │ └── jdbc-source.json ├── docs ├── dependencies.png ├── search.png └── trace.png ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── etc └── header.txt ├── main └── java │ └── brave │ └── kafka │ └── interceptor │ ├── KafkaInterceptorPropagation.java │ ├── KafkaInterceptorTagKey.java │ ├── TracingBuilder.java │ ├── TracingConfiguration.java │ ├── TracingConsumerInterceptor.java │ └── TracingProducerInterceptor.java └── test ├── java └── brave │ └── kafka │ └── interceptor │ ├── BaseTracingTest.java │ ├── TracingBuilderTest.java │ ├── TracingConfigurationTest.java │ ├── TracingConsumerInterceptorTest.java │ └── TracingProducerInterceptorTest.java └── resources └── log4j2.properties /.editorconfig: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2018 The OpenZipkin 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 | root = true 16 | 17 | [*] 18 | charset = utf-8 19 | end_of_line = lf 20 | indent_style = space 21 | indent_size = 2 22 | insert_final_newline = true 23 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Zipkin 2 | 3 | If you would like to contribute code, fork this GitHub repository and 4 | send a pull request (on a branch other than `master` or `gh-pages`). 5 | 6 | When submitting code, please apply [Square Code Style](https://github.com/square/java-code-styles). 7 | * If the settings import correctly, CodeStyle/Java will be named Square and use 2 space tab and indent, with 4 space continuation indent. 8 | 9 | ## License 10 | 11 | By contributing your code, you agree to license your contribution under 12 | the terms of the [APLv2](../LICENSE). 13 | 14 | All files are released with the Apache 2.0 license. 15 | 16 | If you are adding a new file it should have a header like below. This 17 | can be automatically added by running `./mvnw com.mycila:license-maven-plugin:format`. 18 | 19 | ``` 20 | /** 21 | * Copyright 2019 The OpenZipkin Authors 22 | * 23 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 24 | * in compliance with the License. You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software distributed under the License 29 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 30 | * or implied. See the License for the specific language governing permissions and limitations under 31 | * the License. 32 | */ 33 | ``` 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 3 | about: If you’ve found a bug, spend the time to write a failing test. Bugs with tests get fixed and stay fixed. If you have a solution in mind, skip raising an issue and open a pull request instead. 4 | labels: bug 5 | --- 6 | ## Describe the Bug 7 | A clear and concise description of what the bug is. If you have a solution in mind, skip raising an issue and open a pull request instead. 8 | 9 | Regardless, the best is to spend some time to write a failing test. Bugs with tests get fixed and stay fixed. 10 | 11 | ## Steps to Reproduce 12 | Steps to reproduce the behavior: 13 | 14 | ## Expected Behaviour 15 | Suggest what you think correct behaviour should be. Note, it may be solved differently depending on the problem. 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Question 4 | url: https://gitter.im/openzipkin/zipkin 5 | about: Please ask questions about how to do something or to understand why something isn't working on our Gitter chat - we'll be happy to respond there in detail. This issue tracker is not for questions. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Please first, look at existing issues to see if the feature has been requested before. 4 | labels: enhancement 5 | --- 6 | Please first, look at [existing issues](https://github.com/openzipkin-contrib/brave-kafka-interceptor/issues) to see if the feature has been requested before. If you don't find anything tell us what problem you’re trying to solve. Often a solution already exists! Don’t send pull requests to implement new features without first getting our support. Sometimes we leave features out on purpose to keep the project small. 7 | 8 | ## Feature 9 | Description of the feature 10 | 11 | ## Rationale 12 | Why would this feature help others besides me? 13 | 14 | ## Example Scenario 15 | What kind of use cases would benefit from this feature? 16 | 17 | ## Prior Art 18 | * Links to prior art 19 | * More links 20 | -------------------------------------------------------------------------------- /.github/workflows/create_release.yml: -------------------------------------------------------------------------------- 1 | # yamllint --format github .github/workflows/create_release.yml 2 | --- 3 | name: create_release 4 | 5 | # We create a release version on a trigger tag, regardless of if the commit is documentation-only. 6 | # 7 | # See https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet 8 | on: 9 | push: 10 | tags: 'release-[0-9]+.[0-9]+.[0-9]+**' # Ex. release-1.2.3 11 | 12 | jobs: 13 | create_release: 14 | runs-on: ubuntu-20.04 # newest available distribution, aka focal 15 | steps: 16 | - name: Checkout Repository 17 | uses: actions/checkout@v2 18 | with: 19 | # Prevent use of implicit GitHub Actions read-only token GITHUB_TOKEN. We don't deploy on 20 | # the tag MAJOR.MINOR.PATCH event, but we still need to deploy the maven-release-plugin master commit. 21 | token: ${{ secrets.GH_TOKEN }} 22 | fetch-depth: 1 # only need the base commit as license check isn't run 23 | - name: Cache local Maven repository 24 | uses: actions/cache@v2 25 | with: 26 | path: ~/.m2/repository 27 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 28 | restore-keys: ${{ runner.os }}-maven- 29 | - name: Create Release 30 | env: 31 | # GH_USER= 32 | GH_USER: ${{ secrets.GH_USER }} 33 | # GH_TOKEN= 34 | # - makes release commits and tags 35 | # - needs repo:status, public_repo 36 | # - referenced in .settings.xml 37 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 38 | run: | # GITHUB_REF will be refs/tags/release-MAJOR.MINOR.PATCH 39 | build-bin/git/login_git && 40 | build-bin/maven/maven_release $(echo ${GITHUB_REF} | cut -d/ -f 3) 41 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # yamllint --format github .github/workflows/deploy.yml 2 | --- 3 | name: deploy 4 | 5 | # We deploy on master and release versions, regardless of if the commit is 6 | # documentation-only or not. 7 | # 8 | # See https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet 9 | on: 10 | push: 11 | # Don't deploy tags as they conflict with [maven-release-plugin] prepare release MAJOR.MINOR.PATCH 12 | tags: '' 13 | branches: master 14 | 15 | jobs: 16 | deploy: 17 | runs-on: ubuntu-20.04 # newest available distribution, aka focal 18 | steps: 19 | - name: Checkout Repository 20 | uses: actions/checkout@v2 21 | with: 22 | fetch-depth: 1 # only needed to get the sha label 23 | - name: Cache local Maven repository 24 | uses: actions/cache@v2 25 | with: 26 | path: ~/.m2/repository 27 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 28 | restore-keys: ${{ runner.os }}-maven- 29 | - name: Deploy 30 | env: 31 | GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} 32 | # GPG_PASSPHRASE= 33 | # - referenced in .settings.xml 34 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 35 | # SONATYPE_USER= 36 | # - deploys snapshots and releases to Sonatype 37 | # - needs access to io.zipkin via https://issues.sonatype.org/browse/OSSRH-16669 38 | # - generate via https://oss.sonatype.org/#profile;User%20Token 39 | # - referenced in .settings.xml 40 | SONATYPE_USER: ${{ secrets.SONATYPE_USER }} 41 | # SONATYPE_PASSWORD= 42 | # - referenced in .settings.xml 43 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 44 | run: | # GITHUB_REF will be refs/heads/master or refs/tags/MAJOR.MINOR.PATCH 45 | build-bin/configure_deploy && 46 | build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3) 47 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # yamllint --format github .github/workflows/test.yml 2 | --- 3 | name: test 4 | 5 | # We don't test documentation-only commits. 6 | on: 7 | # We run tests on non-tagged pushes to master that aren't a commit made by the release plugin 8 | push: 9 | tags: '' 10 | branches: master 11 | paths-ignore: '**/*.md' 12 | # We also run tests on pull requests targeted at the master branch. 13 | pull_request: 14 | branches: master 15 | paths-ignore: '**/*.md' 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-20.04 # newest available distribution, aka focal 20 | if: "!contains(github.event.head_commit.message, 'maven-release-plugin')" 21 | steps: 22 | - name: Checkout Repository 23 | uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 # full git history for license check 26 | - name: Cache local Maven repository 27 | uses: actions/cache@v2 28 | with: 29 | path: ~/.m2/repository 30 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 31 | restore-keys: ${{ runner.os }}-maven- 32 | # We can't cache Docker without using buildx because GH actions restricts /var/lib/docker 33 | # That's ok because DOCKER_PARENT_IMAGE is always ghcr.io and local anyway. 34 | - name: Test 35 | run: build-bin/configure_test && build-bin/test 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 4 | hs_err_pid* 5 | 6 | # Maven 7 | target/ 8 | 9 | # IntelliJ 10 | .idea/ 11 | *.iml 12 | 13 | # macOS 14 | .DS_Store 15 | 16 | # Eclipse 17 | .classpath 18 | .project 19 | .settings/ 20 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openzipkin-contrib/brave-kafka-interceptor/755272b5b3979e8fe233fbd300c7fbe30edd8362/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 21 | 22 | 23 | gpg.passphrase 24 | ${env.GPG_PASSPHRASE} 25 | 26 | 27 | ossrh 28 | ${env.SONATYPE_USER} 29 | ${env.SONATYPE_PASSWORD} 30 | 31 | 32 | github.com 33 | zipkinci 34 | ${env.GH_TOKEN} 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAVEN := ./mvnw 2 | 3 | .PHONY: all 4 | all: build 5 | 6 | .PHONY: license-header 7 | license-header: 8 | ${MAVEN} com.mycila:license-maven-plugin:format 9 | 10 | .PHONY: build 11 | build: license-header 12 | ${MAVEN} clean package 13 | 14 | .PHONY: docker-up 15 | docker-up: build 16 | docker-compose up -d 17 | 18 | .PHONY: pg-table 19 | pg-table: 20 | docker-compose exec postgres psql -U postgres -c 'CREATE TABLE source_table (id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL)' 21 | 22 | .PHONY: kafka-connectors 23 | kafka-connectors: 24 | curl -XPUT -H 'Content-Type:application/json' -d @docker/kafka-connector/jdbc-source.json http://localhost:8083/connectors/jdbc_source/config 25 | curl -XPUT -H 'Content-Type:application/json' -d @docker/kafka-connector/jdbc-sink.json http://localhost:8083/connectors/jdbc_sink/config 26 | 27 | .PHONY: pg-row 28 | pg-row: 29 | docker-compose exec postgres psql -U postgres -c 'INSERT INTO source_table ( name ) VALUES (MD5(random()::text))' 30 | 31 | .PHONY: ksql-stream 32 | ksql-stream: 33 | docker-compose exec ksql-cli bash -c \ 34 | 'echo -e "\ 35 | CREATE STREAM source_stream (id BIGINT, name VARCHAR) WITH (KAFKA_TOPIC='"'"'jdbc_source_table'"'"', VALUE_FORMAT='"'"'AVRO'"'"'); \ 36 | SHOW STREAMS;" \ 37 | | ksql http://ksql-server:8088' 38 | 39 | .PHONY: ksql-select 40 | ksql-select: 41 | docker-compose exec ksql-cli bash -c \ 42 | 'echo -e "\ 43 | CREATE STREAM another_stream \ 44 | AS SELECT id, name \ 45 | FROM source_stream \ 46 | EMIT CHANGES;" \ 47 | | ksql http://ksql-server:8088' 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brave: Kafka Interceptor 2 | 3 | [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/openzipkin/zipkin) 4 | [![Build Status](https://github.com/openzipkin-contrib/brave-kafka-interceptor/workflows/test/badge.svg)](https://github.com/openzipkin-contrib/brave-kafka-interceptor/actions?query=workflow%3Atest) 5 | [![Maven Central](https://img.shields.io/maven-central/v/io.zipkin.contrib.brave-kafka-interceptor/brave-kafka-interceptor.svg)](https://search.maven.org/search?q=g:io.zipkin.contrib.brave-kafka-interceptor%20AND%20a:brave-kafka-interceptor) 6 | 7 | Kafka [Consumer](https://kafka.apache.org/0100/javadoc/org/apache/kafka/clients/consumer/ConsumerInterceptor.html) 8 | and [Producer](https://kafka.apache.org/0100/javadoc/org/apache/kafka/clients/producer/ProducerInterceptor.html) 9 | Interceptors for tracing and report to Zipkin. 10 | 11 | These interceptors could be plugged into Kafka applications via classpath configuration. 12 | 13 | The purpose of this instrumentation is to enable tracing for Kafka Connect and other off-the-shelf components like Kafka REST Proxy, ksqlDB, etc. 14 | For more complete tracing support, check [Brave instrumentation](https://github.com/openzipkin/brave) for [Kafka Clients](https://github.com/openzipkin/brave/tree/master/instrumentation/kafka-clients) and [Kafka Streams](https://github.com/openzipkin/brave/tree/master/instrumentation/kafka-streams). 15 | 16 | ## Installation 17 | 18 | ### Producer Interceptor 19 | 20 | Producer Interceptor create spans when sending records. This span will only represent the time it took to 21 | execute the `on_send` method provided by the API, not how long to send the actual record, or any other latency. 22 | 23 | #### Kafka Clients 24 | 25 | Add Interceptor to Producer Configuration: 26 | 27 | ```java 28 | producerConfig.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, Collections.singletonList(TracingProducerInterceptor.class)); 29 | //or 30 | producerConfig.put("interceptor.classes", "brave.kafka.interceptor.TracingProducerInterceptor"); 31 | ``` 32 | ### Consumer Interceptor 33 | 34 | Consumer Interceptor create spans on consumption of records. This span will only represent the time it took execute 35 | the `on_consume` method provided by the API, not how long it took to commit, or any other latency. 36 | 37 | #### Kafka Clients 38 | 39 | ```java 40 | consumerConfig.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, Collections.singletonList(TracingConsumerInterceptor.class)); 41 | //or 42 | consumerConfig.put("interceptor.classes", "brave.kafka.interceptor.TracingConsumerInterceptor"); 43 | ``` 44 | 45 | ### Configuration 46 | 47 | | Key | Value | 48 | |----------------------------------|---------------------------------------------------------------------------------------------------------| 49 | | `zipkin.sender.type` | Sender type: `NONE`(default), `KAFKA`, `HTTP` | 50 | | `zipkin.encoding` | Zipkin encoding: `JSON`(default), `PROTO3`. | 51 | | `zipkin.http.endpoint` | Zipkin HTTP Endpoint sender. | 52 | | `zipkin.kafka.bootstrap.servers` | Bootstrap Servers list to send Spans. if not present, `bootstrap.servers` (Kafka Client property) is used. | 53 | | `zipkin.local.service.name` | Application Service name used to tag span. Default: kafka-client. | 54 | | `zipkin.trace.id.128bit.enabled` | Trace ID 128 bit enabled, default: `true` | 55 | | `zipkin.sampler.rate` | Rate to sample spans. Default: `1.0` | 56 | | `zipkin.kafka.*` | Use this prefix to override any kafka producer property | 57 | 58 | ### How to test it 59 | 60 | Required software available: 61 | 62 | - Docker and Docker Compose available. 63 | - JDK 11+ 64 | 65 | Start by building libraries and run Docker Compose: 66 | 67 | ```shell script 68 | make docker-up # will build jars and start containers 69 | # or 70 | ./mvnw clean package 71 | docker-compose up -d 72 | ``` 73 | 74 | Create database tables: 75 | 76 | ```shell script 77 | make pg-table 78 | ``` 79 | 80 | Once table is created deploy source and sink connectors: 81 | 82 | ```shell script 83 | make kafka-connectors 84 | ``` 85 | 86 | Create a KSQL table and select to wait for results: 87 | 88 | ```shell script 89 | make ksql-stream 90 | make ksql-select 91 | ``` 92 | 93 | Insert new rows: 94 | 95 | ```shell script 96 | make pg-row 97 | ``` 98 | 99 | Go to Check the traces. 100 | 101 | 102 | Traces should look like this: 103 | 104 | Search: 105 | 106 | ![](docs/search.png) 107 | 108 | Trace view: 109 | 110 | ![](docs/trace.png) 111 | 112 | Dependencies: 113 | 114 | ![](docs/dependencies.png) 115 | 116 | ## Artifacts 117 | All artifacts publish to the group ID "io.zipkin.contrib.brave-kafka-interceptor". We use a common 118 | release version for all components. 119 | 120 | ### Library Releases 121 | Releases are at [Sonatype](https://oss.sonatype.org/content/repositories/releases) and [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.zipkin.contrib.brave-kafka-interceptor%22) 122 | 123 | ### Library Snapshots 124 | Snapshots are uploaded to [Sonatype](https://oss.sonatype.org/content/repositories/snapshots) after 125 | commits to master. 126 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # OpenZipkin Release Process 2 | 3 | This repo uses semantic versions. Please keep this in mind when choosing version numbers. 4 | 5 | 1. **Alert others you are releasing** 6 | 7 | There should be no commits made to master while the release is in progress (about 10 minutes). Before you start 8 | a release, alert others on [gitter](https://gitter.im/openzipkin/zipkin) so that they don't accidentally merge 9 | anything. If they do, and the build fails because of that, you'll have to recreate the release tag described below. 10 | 11 | 1. **Push a git tag** 12 | 13 | The trigger format is `release-MAJOR.MINOR.PATCH`, ex `git tag release-1.18.1 && git push origin release-1.18.1`. 14 | 15 | 1. **Wait for CI** 16 | 17 | The `release-MAJOR.MINOR.PATCH` tag triggers [`build-bin/maven/maven_release`](build-bin/maven/maven_release), 18 | which creates commits, `MAJOR.MINOR.PATCH` tag, and increments the version (maven-release-plugin). 19 | 20 | The `MAJOR.MINOR.PATCH` tag triggers [`build-bin/deploy`](build-bin/deploy), which does the following: 21 | * Publishes jars to https://oss.sonatype.org/content/repositories/releases [`build-bin/maven/maven_deploy`](build-bin/maven/maven_deploy) 22 | * Later, the same jars synchronize to Maven Central 23 | 24 | Notes: 25 | * https://search.maven.org/ index will take longer than direct links like https://repo1.maven.org/maven2/io/zipkin 26 | 27 | ## Credentials 28 | 29 | The release process uses various credentials. If you notice something failing due to unauthorized, 30 | look at the notes in [.github/workflows/deploy.yml] and check the [org secrets](https://github.com/organizations/openzipkin-contrib/settings/secrets/actions). 31 | 32 | ### Troubleshooting invalid credentials 33 | 34 | If you receive a '401 unauthorized' failure from OSSRH, it is likely 35 | `SONATYPE_USER` or `SONATYPE_PASSWORD` entries are invalid, or possibly the 36 | user associated with them does not have rights to upload. 37 | 38 | The least destructive test is to try to publish a snapshot manually. By passing 39 | the values CI would use, you can kick off a snapshot from your laptop. This 40 | is a good way to validate that your unencrypted credentials are authorized. 41 | 42 | Here's an example of a snapshot deploy with specified credentials. 43 | ```bash 44 | $ export GPG_TTY=$(tty) && GPG_PASSPHRASE=whackamole SONATYPE_USER=adrianmole SONATYPE_PASSWORD=ed6f20bde9123bbb2312b221 build-bin/build-bin/maven/maven_deploy 45 | ``` 46 | 47 | ## First release of the year 48 | 49 | The license plugin verifies license headers of files include a copyright notice indicating the years a file was affected. 50 | This information is taken from git history. There's a once-a-year problem with files that include version numbers (pom.xml). 51 | When a release tag is made, it increments version numbers, then commits them to git. On the first release of the year, 52 | further commands will fail due to the version increments invalidating the copyright statement. The way to sort this out is 53 | the following: 54 | 55 | Before you do the first release of the year, move the SNAPSHOT version back and forth from whatever the current is. 56 | In-between, re-apply the licenses. 57 | ```bash 58 | $ ./mvnw versions:set -DnewVersion=1.3.3-SNAPSHOT -DgenerateBackupPoms=false 59 | $ ./mvnw com.mycila:license-maven-plugin:format 60 | $ ./mvnw versions:set -DnewVersion=1.3.2-SNAPSHOT -DgenerateBackupPoms=false 61 | $ git commit -am"Adjusts copyright headers for this year" 62 | ``` 63 | 64 | ## Manually releasing 65 | 66 | If for some reason, you lost access to CI or otherwise cannot get automation to work, bear in mind 67 | this is a normal maven project, and can be released accordingly. 68 | 69 | *Note:* If [Sonatype is down](https://status.sonatype.com/), the below will not work. 70 | 71 | ```bash 72 | # First, set variable according to your personal credentials. These would normally be assigned as 73 | # org secrets: https://github.com/organizations/openzipkin/settings/secrets/actions 74 | export GPG_TTY=$(tty) 75 | export GPG_PASSPHRASE=your_gpg_passphrase 76 | export SONATYPE_USER=your_sonatype_account 77 | export SONATYPE_PASSWORD=your_sonatype_password 78 | release_version=xx-version-to-release-xx 79 | 80 | # now from latest master, create the release. This creates and pushes the MAJOR.MINOR.PATCH tag 81 | ./build-bin/maven/maven_release release-${release_version} 82 | 83 | # once this works, deploy the release 84 | git checkout ${release_version} 85 | ./build-bin/deploy 86 | 87 | # Finally, clean up 88 | ./mvnw release:clean 89 | git checkout master 90 | git reset HEAD --hard 91 | ``` 92 | -------------------------------------------------------------------------------- /build-bin/README.md: -------------------------------------------------------------------------------- 1 | # Test and Deploy scripts 2 | 3 | This is a Maven project, which uses standard conventions for test and deploy. 4 | 5 | [//]: # (Below here should be standard for all projects) 6 | 7 | ## Build Overview 8 | `build-bin` holds portable scripts used in CI to test and deploy the project. 9 | 10 | The scripts here are portable. They do not include any CI provider-specific logic or ENV variables. 11 | This helps `.travis.yml` and `test.yml` (GitHub Actions) contain nearly the same contents, even if 12 | certain OpenZipkin projects need slight adjustments here. Portability has proven necessary, as 13 | OpenZipkin has had to transition CI providers many times due to feature and quota constraints. 14 | 15 | These scripts serve a second purpose, which is to facilitate manual releases, which has also 16 | happened many times due usually to service outages of CI providers. While tempting to use 17 | CI-provider specific tools, doing so can easily create a dependency where no one knows how to 18 | release anymore. Do not use provider-specific mechanisms to implement release flow. Instead, 19 | automate triggering of the scripts here. 20 | 21 | The only scripts that should be modified per project are in the base directory. Those in sub 22 | directories, such as [docker], should not vary project to project except accident of version drift. 23 | Intentional changes in sub directories should be relevant and tested on multiple projects to ensure 24 | they can be blindly copy/pasted. 25 | 26 | Conversely, the files in the base directory are project specific entry-points for test and deploy 27 | actions and are entirely appropriate to vary per project. Here's an overview: 28 | 29 | ## Test 30 | 31 | Test builds and runs any tests of the project, including integration tests. CI providers should be 32 | configured to run tests on pull requests or pushes to the master branch, notably when the tag is 33 | blank. Tests should not run on documentation-only commits. Tests must not depend on authenticated 34 | resources, as running tests can leak credentials. Git checkouts should include the full history so 35 | that license headers or other git analysis can take place. 36 | 37 | * [configure_test] - Sets up build environment for tests. 38 | * [test] - Builds and runs tests for this project. 39 | 40 | ### Example GitHub Actions setup 41 | 42 | A simplest GitHub Actions `test.yml` runs tests after configuring them, but only on relevant event 43 | conditions. The name `test.yml` and job `test` allows easy references to status badges and parity of 44 | the scripts it uses. 45 | 46 | The `on:` section obviates job creation and resource usage for irrelevant events. Notably, GitHub 47 | Actions includes the ability to skip documentation-only jobs. 48 | 49 | Combine [configure_test] and [test] into the same `run:` when `configure_test` primes file system 50 | cache. 51 | 52 | Here's a partial `test.yml` including only the aspects mentioned above. 53 | ```yaml 54 | on: 55 | push: 56 | tags: '' 57 | branches: master 58 | paths-ignore: '**/*.md' 59 | pull_request: 60 | branches: master 61 | paths-ignore: '**/*.md' 62 | 63 | jobs: 64 | test: 65 | steps: 66 | - name: Checkout Repository 67 | uses: actions/checkout@v2 68 | with: 69 | fetch-depth: 0 # full git history 70 | - name: Test 71 | run: build-bin/configure_test && build-bin/test 72 | ``` 73 | 74 | ### Example Travis setup 75 | `.travis.yml` is a monolithic configuration file broken into stages, of which the default is "test". 76 | A simplest Travis `test` job configures tests in `install` and runs them as `script`, but only on 77 | relevant event conditions. 78 | 79 | The `if:` section obviates job creation and resource usage for irrelevant events. Travis does not 80 | support file conditions. A `before_install` step to skip documentation-only commits will likely 81 | complete in less than a minute (10 credit cost). 82 | 83 | Here's a partial `.travis.yml` including only the aspects mentioned above. 84 | ```yaml 85 | git: 86 | depth: false # TRAVIS_COMMIT_RANGE requires full commit history. 87 | 88 | jobs: 89 | include: 90 | - stage: test 91 | if: branch = master AND tag IS blank AND type IN (push, pull_request) 92 | name: Run unit and integration tests 93 | before_install: | # Prevent test build of a documentation-only change. 94 | if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then 95 | echo "Stopping job as changes only affect documentation (ex. README.md)" 96 | travis_terminate 0 97 | fi 98 | install: ./build-bin/configure_test 99 | script: ./build-bin/test 100 | ``` 101 | 102 | When Travis only runs tests (something else does deploy), there's no need to use stages: 103 | ```yaml 104 | git: 105 | depth: false # TRAVIS_COMMIT_RANGE requires full commit history. 106 | 107 | if: branch = master AND tag IS blank AND type IN (push, pull_request) 108 | before_install: | # Prevent test build of a documentation-only change. 109 | if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then 110 | echo "Stopping job as changes only affect documentation (ex. README.md)" 111 | travis_terminate 0 112 | fi 113 | install: ./build-bin/configure_test 114 | script: ./build-bin/test 115 | ``` 116 | 117 | ## Deploy 118 | 119 | Deploy builds and pushes artifacts to a remote repository for master and release commits on it. CI 120 | providers deploy pushes to master on when the tag is blank, but not on documentation-only commits. 121 | Releases should deploy on version tags (ex `/^[0-9]+\.[0-9]+\.[0-9]+/`), without consideration of if 122 | the commit is documentation only or not. 123 | 124 | * [configure_deploy] - Sets up environment and logs in, assuming [configure_test] was not called. 125 | * [deploy] - deploys the project, with arg0 being "master" or a release commit like "1.2.3" 126 | 127 | ### Example GitHub Actions setup 128 | 129 | A simplest GitHub Actions `deploy.yml` deploys after logging in, but only on relevant event 130 | conditions. The name `deploy.yml` and job `deploy` allows easy references to status badges and 131 | parity of the scripts it uses. 132 | 133 | The `on:` section obviates job creation and resource usage for irrelevant events. GitHub Actions 134 | cannot implement "master, except documentation only-commits" in the same file. Hence, deployments of 135 | master will happen even on README change. 136 | 137 | Combine [configure_deploy] and [deploy] into the same `run:` when `configure_deploy` primes file 138 | system cache. 139 | 140 | Here's a partial `deploy.yml` including only the aspects mentioned above. Notice env variables are 141 | explicitly defined and `on.tags` is a [glob pattern](https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet). 142 | ```yaml 143 | on: 144 | push: 145 | tags: '[0-9]+.[0-9]+.[0-9]+**' # Ex. 8.272.10 or 15.0.1_p9 146 | branches: master 147 | 148 | jobs: 149 | deploy: 150 | steps: 151 | - name: Checkout Repository 152 | uses: actions/checkout@v2 153 | with: 154 | fetch-depth: 1 # only needed to get the sha label 155 | - name: Deploy 156 | env: 157 | GH_USER: ${{ secrets.GH_USER }} 158 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 159 | run: | # GITHUB_REF will be refs/heads/master or refs/tags/MAJOR.MINOR.PATCH 160 | build-bin/configure_deploy && 161 | build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3) 162 | ``` 163 | 164 | ### Example Travis setup 165 | `.travis.yml` is a monolithic configuration file broken into stages. This means `test` and `deploy` 166 | are in the same file. A simplest Travis `deploy` stage has two jobs: one for master pushes and 167 | another for version tags. These jobs are controlled by event conditions. 168 | 169 | The `if:` section obviates job creation and resource usage for irrelevant events. Travis does not 170 | support file conditions. A `before_install` step to skip documentation-only commits will likely 171 | complete in less than a minute (10 credit cost). 172 | 173 | As billing is by the minute, it is most cost effective to combine test and deploy on master push. 174 | 175 | Here's a partial `.travis.yml` including only the aspects mentioned above. Notice YAML anchors work 176 | in Travis and `tag =~` [condition](https://github.com/travis-ci/travis-conditions) is a regular 177 | expression. 178 | ```yaml 179 | git: 180 | depth: false # full git history for license check, and doc-only skipping 181 | 182 | _terminate_if_only_docs: &terminate_if_only_docs | 183 | if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then 184 | echo "Stopping job as changes only affect documentation (ex. README.md)" 185 | travis_terminate 0 186 | fi 187 | 188 | jobs: 189 | include: 190 | - stage: test 191 | if: branch = master AND tag IS blank AND type IN (push, pull_request) 192 | before_install: *terminate_if_only_docs 193 | install: | 194 | if [ "${TRAVIS_SECURE_ENV_VARS}" = "true" ] && [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then 195 | export SHOULD_DEPLOY=true 196 | ./build-bin/configure_deploy 197 | else 198 | export SHOULD_DEPLOY=false 199 | ./build-bin/configure_test 200 | fi 201 | script: 202 | - ./build-bin/test || travis_terminate 1 203 | - if [ "${SHOULD_DEPLOY}" != "true" ]; then travis_terminate 0; fi 204 | - travis_wait ./build-bin/deploy master 205 | - stage: deploy 206 | # Ex. 8.272.10 or 15.0.1_p9 207 | if: tag =~ /^[0-9]+\.[0-9]+\.[0-9]+/ AND type = push AND env(GH_TOKEN) IS present 208 | install: ./build-bin/configure_deploy 209 | script: ./build-bin/deploy ${TRAVIS_TAG} 210 | ``` 211 | -------------------------------------------------------------------------------- /build-bin/configure_deploy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ue 2 | 3 | # This script sets up anything needed for `./deploy`. Do not assume `configure_test` was called. 4 | # 5 | # See [README.md] for an explanation of this and how CI should use it. 6 | build-bin/maven/maven_go_offline 7 | build-bin/gpg/configure_gpg 8 | -------------------------------------------------------------------------------- /build-bin/configure_test: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ue 2 | 3 | # This script sets up anything needed for `./test`. This should not login to anything, as that 4 | # should be done in `configure_deploy`. 5 | # 6 | # See [README.md] for an explanation of this and how CI should use it. 7 | build-bin/maven/maven_go_offline 8 | 9 | # Ensure testcontainers are configured properly 10 | build-bin/docker/configure_docker 11 | -------------------------------------------------------------------------------- /build-bin/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ue 2 | 3 | # This script deploys a master or release version. 4 | # 5 | # See [README.md] for an explanation of this and how CI should use it. 6 | build-bin/maven/maven_deploy 7 | -------------------------------------------------------------------------------- /build-bin/docker/configure_docker: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | # Defends against build outages caused by Docker Hub (docker.io) pull rate limits. 17 | # 18 | # It should not login to anything, as that should be done in `configure_docker_push` 19 | 20 | set -ue 21 | 22 | # The below sets up testcontainers configuration, which will be ignored if it isn't used. Even if 23 | # this is Docker related, it is coupled to integration tests configuration invoked with Maven. 24 | # * See https://www.testcontainers.org/supported_docker_environment/image_registry_rate_limiting/ 25 | # * checks.disable=true - saves time and a docker.io pull of alpine 26 | # * ryuk doesn't count against docker.io rate limits because Docker approved testcontainers as OSS 27 | echo checks.disable=true >> ~/.testcontainers.properties 28 | # * upgrade ryuk until https://github.com/testcontainers/testcontainers-java/pull/3630 29 | echo ryuk.container.image=testcontainers/ryuk:0.3.1 >> ~/.testcontainers.properties 30 | 31 | # We don't use any docker.io images, but add a Google's mirror in case something implicitly does 32 | # * See https://cloud.google.com/container-registry/docs/pulling-cached-images 33 | echo '{ "registry-mirrors": ["https://mirror.gcr.io"] }' | sudo tee /etc/docker/daemon.json 34 | sudo service docker restart 35 | 36 | # * Ensure buildx and related features are disabled 37 | mkdir -p ${HOME}/.docker && echo '{"experimental":"disabled"}' > ${HOME}/.docker/config.json 38 | -------------------------------------------------------------------------------- /build-bin/git/login_git: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | set -ue 17 | 18 | # Allocate commits to CI, not the owner of the deploy key 19 | git config user.name "zipkinci" 20 | git config user.email "zipkinci+zipkin-dev@googlegroups.com" 21 | 22 | # Setup https authentication credentials, used by ./mvnw release:prepare 23 | git config credential.helper "store --file=.git/credentials" 24 | echo "https://$GH_TOKEN:@github.com" > .git/credentials 25 | -------------------------------------------------------------------------------- /build-bin/git/version_from_trigger_tag: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | set -ue 17 | 18 | # This script echos a `MAJOR.MINOR.PATCH` version tag based on.. 19 | # * arg1: XXXXX- prefix 20 | # * arg2: XXXXX-MAJOR.MINOR.PATCH git trigger tag 21 | # 22 | # The script exits 1 if the prefix doesn't match. On success, the tag is deleted if it exists. 23 | # 24 | # Note: In CI, `build-bin/git/login_git` must be called before invoking this. 25 | 26 | trigger_tag_prefix=${1?required. Ex docker- to match docker-1.2.3} 27 | trigger_tag=${2?trigger_tag is required. Ex ${trigger_tag_prefix}1.2.3} 28 | 29 | # Checking sed output to determine success as exit code handling in sed or awk is awkward 30 | version=$(echo "${trigger_tag}" | sed -En "s/^${trigger_tag_prefix}([0-9]+\.[0-9]+\.[0-9]+)$/\1/p") 31 | 32 | if [ -z "$version" ]; then 33 | >&2 echo invalid trigger tag: ${trigger_tag} 34 | exit 1; 35 | fi 36 | 37 | # try to cleanup the trigger tag if it exists, but don't fail if it doesn't 38 | git tag -d ${trigger_tag} 2>&- >&- || true 39 | git push origin :${trigger_tag} 2>&- >&- || true 40 | 41 | echo $version 42 | -------------------------------------------------------------------------------- /build-bin/gpg/configure_gpg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | set -ue 17 | 18 | # This script prepares GPG, needed to sign jars for Sonatype deployment during `maven_deploy` 19 | 20 | # ensure GPG commands work non-interactively 21 | export GPG_TTY=$(tty) 22 | # import signing key used for jar files 23 | echo ${GPG_SIGNING_KEY} | base64 --decode | gpg --batch --passphrase ${GPG_PASSPHRASE} --import 24 | -------------------------------------------------------------------------------- /build-bin/maven/maven_deploy: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | set -ue 17 | 18 | export MAVEN_OPTS="$($(dirname "$0")/maven_opts)" 19 | 20 | # This script deploys a SNAPSHOT or release version to Sonatype. 21 | # 22 | # Note: In CI, `configure_maven_deploy` must be called before invoking this. 23 | ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DskipTests clean deploy $@ 24 | -------------------------------------------------------------------------------- /build-bin/maven/maven_go_offline: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | # This is a go-offline that properly works with multi-module builds 17 | 18 | set -ue 19 | 20 | export MAVEN_OPTS="$($(dirname "$0")/maven_opts)" 21 | if [ -x ./mvnw ]; then alias mvn=${PWD}/mvnw; fi 22 | 23 | ( 24 | if [ "${MAVEN_PROJECT_BASEDIR:-.}" != "." ]; then cd ${MAVEN_PROJECT_BASEDIR}; fi 25 | mvn -q --batch-mode -nsu -Prelease de.qaware.maven:go-offline-maven-plugin:resolve-dependencies "$@" 26 | ) 27 | -------------------------------------------------------------------------------- /build-bin/maven/maven_opts: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | # This script checks each variable value, so it isn't important to fail on unbound (set -u) 17 | set -e 18 | 19 | maven_project_basedir=${MAVEN_PROJECT_BASEDIR:-.} 20 | pom="${maven_project_basedir}/pom.xml" 21 | 22 | # fail if there's no pom 23 | test -f "${pom}" 24 | 25 | arch=$(uname -m) 26 | case ${arch} in 27 | arm64* ) 28 | arch=arm64 29 | ;; 30 | aarch64* ) 31 | arch=arm64 32 | ;; 33 | esac 34 | 35 | maven_opts="${MAVEN_OPTS:-}" 36 | if [ ${arch} = "arm64" ] && [ -f /etc/alpine-release ]; then 37 | # Defensively avoid arm64+alpine problems with posix_spawn 38 | maven_opts="${maven_opts} -Djdk.lang.Process.launchMechanism=vfork" 39 | fi 40 | 41 | echo ${maven_opts} 42 | -------------------------------------------------------------------------------- /build-bin/maven/maven_release: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2018-2020 The OpenZipkin Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License 11 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | # or implied. See the License for the specific language governing permissions and limitations under 13 | # the License. 14 | # 15 | 16 | set -ue 17 | 18 | # This script creates a git `MAJOR.MINOR.PATCH` version tag which later will have `deploy` run against it. 19 | # 20 | # In CI.. 21 | # * trigger pattern: tag =~ /^release-[0-9]+\.[0-9]+\.[0-9]+/ 22 | # * build-bin/git/login_git must be called before invoking this. 23 | 24 | export MAVEN_OPTS="$($(dirname "$0")/maven_opts)" 25 | 26 | trigger_tag=${1?trigger_tag is required. Ex release-1.2.3} 27 | release_version=$(build-bin/git/version_from_trigger_tag release- ${trigger_tag}) 28 | release_branch=${2:-master} 29 | 30 | # Checkout master, as we release from master, not a tag ref 31 | git fetch --no-tags --prune --depth=1 origin +refs/heads/${release_branch}:refs/remotes/origin/${release_branch} 32 | git checkout ${release_branch} 33 | 34 | # Ensure no one pushed commits since this release tag as it would fail later commands 35 | commit_local_release_branch=$(git show --pretty='format:%H' ${release_branch}) 36 | commit_remote_release_branch=$(git show --pretty='format:%H' origin/${release_branch}) 37 | if [ "$commit_local_release_branch" != "$commit_remote_release_branch" ]; then 38 | >&2 echo "${release_branch} on remote 'origin' has commits since the version to release, aborting" 39 | exit 1 40 | fi 41 | 42 | # Prepare and push release commits and the version tag (N.N.N), which triggers deployment. 43 | ./mvnw --batch-mode -nsu -DreleaseVersion=${release_version} -Denforcer.fail=false -Darguments="-DskipTests -Denforcer.fail=false" release:prepare 44 | -------------------------------------------------------------------------------- /build-bin/test: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ue 2 | 3 | # This script runs the tests of the project. 4 | # 5 | # See [README.md] for an explanation of this and how CI should use it. 6 | 7 | # * verify - runs all tests including integration tests 8 | ./mvnw -nsu verify 9 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018-2020 The OpenZipkin 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 | --- 16 | version: '3' 17 | services: 18 | zookeeper: 19 | image: confluentinc/cp-zookeeper:5.5.2 20 | ports: 21 | - 2181:2181 22 | environment: 23 | ZOOKEEPER_CLIENT_PORT: 2181 24 | ZOOKEEPER_TICK_TIME: 2000 25 | kafka: 26 | image: confluentinc/cp-kafka:5.5.2 27 | ports: 28 | - 9092:9092 29 | - 29092:29092 30 | environment: 31 | KAFKA_BROKER_ID: 1 32 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 33 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT 34 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 35 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 36 | KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 37 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 38 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 39 | depends_on: 40 | - zookeeper 41 | zipkin: 42 | image: openzipkin/zipkin 43 | environment: 44 | STORAGE_TYPE: mem 45 | KAFKA_BOOTSTRAP_SERVERS: kafka:9092 46 | ports: 47 | - 9411:9411 48 | 49 | ## Kafka ecosystem 50 | ### Kafka Connectors 51 | postgres: 52 | image: postgres 53 | environment: 54 | POSTGRES_PASSWORD: example 55 | adminer: 56 | image: adminer 57 | ports: 58 | - 8080:8080 59 | schema-registry: 60 | image: confluentinc/cp-schema-registry 61 | ports: 62 | - 8081:8081 63 | environment: 64 | SCHEMA_REGISTRY_HOST_NAME: schema-registry 65 | SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:9092 66 | connect: 67 | image: confluentinc/cp-kafka-connect:5.5.2 68 | ports: 69 | - 8083:8083 70 | environment: 71 | CONNECT_BOOTSTRAP_SERVERS: kafka:9092 72 | CONNECT_REST_ADVERTISED_HOST_NAME: localhost 73 | CONNECT_REST_PORT: 8083 74 | CONNECT_GROUP_ID: jdbc-source-connect 75 | CONNECT_OFFSET_FLUSH_INTERVAL_MS: 10000 76 | CONNECT_CONFIG_STORAGE_TOPIC: connect-configs 77 | CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: 1 78 | CONNECT_OFFSET_STORAGE_TOPIC: connect-offsets 79 | CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: 1 80 | CONNECT_STATUS_STORAGE_TOPIC: connect-status 81 | CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: 1 82 | CONNECT_KEY_CONVERTER: org.apache.kafka.connect.storage.StringConverter 83 | CONNECT_VALUE_CONVERTER: io.confluent.connect.avro.AvroConverter 84 | CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL: http://schema-registry:8081 85 | CONNECT_INTERNAL_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter 86 | CONNECT_INTERNAL_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter 87 | CONNECT_PLUGIN_PATH: /usr/share/java 88 | CONNECT_PRODUCER_INTERCEPTOR_CLASSES: brave.kafka.interceptor.TracingProducerInterceptor 89 | CONNECT_CONSUMER_INTERCEPTOR_CLASSES: brave.kafka.interceptor.TracingConsumerInterceptor 90 | CONNECT_CONNECTOR_CLIENT_CONFIG_OVERRIDE_POLICY: All 91 | volumes: 92 | - ./target/brave-kafka-interceptor-0.5.5-SNAPSHOT.jar:/etc/kafka-connect/jars/brave-kafka-interceptor.jar 93 | ### KSQL 94 | ksql-server: 95 | image: confluentinc/cp-ksqldb-server:5.5.2 96 | ports: 97 | - 8088:8088 98 | depends_on: 99 | - kafka 100 | environment: 101 | KSQL_CUB_KAFKA_TIMEOUT: 300 102 | KSQL_BOOTSTRAP_SERVERS: kafka:9092 103 | KSQL_LISTENERS: http://0.0.0.0:8088 104 | KSQL_KSQL_SCHEMA_REGISTRY_URL: http://schema-registry:8081 105 | KSQL_KSQL_SERVICE_ID: ksql 106 | KSQL_CONSUMER_INTERCEPTOR_CLASSES: brave.kafka.interceptor.TracingConsumerInterceptor 107 | # Removed 'CONSUMER' from the following 2 Zipkin environment variables. 108 | KSQL_ZIPKIN_SENDER_TYPE: KAFKA 109 | KSQL_ZIPKIN_LOCAL_SERVICE_NAME: ksql 110 | volumes: 111 | - ./target/brave-kafka-interceptor-0.5.5-SNAPSHOT.jar:/usr/share/java/ksqldb-server/brave-kafka-interceptor.jar 112 | ksql-cli: 113 | image: confluentinc/cp-ksqldb-cli:5.5.2 114 | depends_on: 115 | - ksql-server 116 | entrypoint: /bin/sh 117 | tty: true 118 | -------------------------------------------------------------------------------- /docker/kafka-connector/jdbc-sink.json: -------------------------------------------------------------------------------- 1 | { 2 | "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector", 3 | "tasks.max": "1", 4 | "topics": "jdbc_source_table", 5 | "connection.url": "jdbc:postgresql://postgres/postgres", 6 | "connection.user": "postgres", 7 | "connection.password": "example", 8 | "auto.create": "true", 9 | "table.prefix": "sink_", 10 | "errors.log.enable": true, 11 | "consumer.override.zipkin.local.service.name": "jdbc-sink-connect", 12 | "consumer.override.zipkin.sender.type": "HTTP", 13 | "consumer.override.zipkin.http.endpoint": "http://zipkin:9411/api/v2/spans" 14 | } 15 | -------------------------------------------------------------------------------- /docker/kafka-connector/jdbc-source.json: -------------------------------------------------------------------------------- 1 | { 2 | "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector", 3 | "tasks.max": "1", 4 | "topic.prefix": "jdbc_", 5 | "connection.url": "jdbc:postgresql://postgres/postgres", 6 | "connection.user": "postgres", 7 | "connection.password": "example", 8 | "table.whitelist": "source_table", 9 | "mode": "incrementing", 10 | "incrementing.column.name": "id", 11 | "errors.log.enable": true, 12 | "producer.override.zipkin.local.service.name": "jdbc-source-connect", 13 | "producer.override.zipkin.sender.type": "HTTP", 14 | "producer.override.zipkin.http.endpoint": "http://zipkin:9411/api/v2/spans" 15 | } 16 | -------------------------------------------------------------------------------- /docs/dependencies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openzipkin-contrib/brave-kafka-interceptor/755272b5b3979e8fe233fbd300c7fbe30edd8362/docs/dependencies.png -------------------------------------------------------------------------------- /docs/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openzipkin-contrib/brave-kafka-interceptor/755272b5b3979e8fe233fbd300c7fbe30edd8362/docs/search.png -------------------------------------------------------------------------------- /docs/trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openzipkin-contrib/brave-kafka-interceptor/755272b5b3979e8fe233fbd300c7fbe30edd8362/docs/trace.png -------------------------------------------------------------------------------- /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 | # Maven 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*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /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 Maven 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 keystroke 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 set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 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 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.zipkin.contrib.brave 21 | brave-kafka-interceptor 22 | 0.6.1-SNAPSHOT 23 | 24 | jar 25 | 26 | 27 | 28 | ossrh 29 | https://oss.sonatype.org/content/repositories/snapshots 30 | 31 | 32 | ossrh 33 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 34 | 35 | 36 | 37 | GitHub 38 | https://github.com/openzipkin-contrib/brave-kafka-interceptor/issues 39 | 40 | 41 | Brave: Kafka Interceptor 42 | Kafka Interceptors to trace send and poll operations with Brave instrumentation. 43 | https://github.com/openzipkin-contrib/brave-kafka-interceptor 44 | 2018 45 | 46 | 47 | OpenZipkin 48 | https://zipkin.io/ 49 | 50 | 51 | 52 | 53 | The Apache Software License, Version 2.0 54 | https://www.apache.org/licenses/LICENSE-2.0.txt 55 | repo 56 | 57 | 58 | 59 | 60 | https://github.com/openzipkin-contrib/brave-kafka-interceptor 61 | scm:git:https://github.com/openzipkin-contrib/brave-kafka-interceptor.git 62 | scm:git:https://github.com/openzipkin-contrib/brave-kafka-interceptor.git 63 | HEAD 64 | 65 | 66 | 67 | 68 | 69 | openzipkin 70 | OpenZipkin Gitter 71 | https://gitter.im/openzipkin/zipkin 72 | 73 | 74 | 75 | 76 | UTF-8 77 | UTF-8 78 | UTF-8 79 | UTF-8 80 | 81 | ${project.basedir} 82 | java18 83 | 84 | 2.7.0 85 | 5.13.3 86 | 87 | 5.7.0 88 | 1.15.1 89 | 3.18.1 90 | 91 | 92 | 93 | 2.4.0 94 | 2.14.0 95 | 96 | ${skipTests} 97 | 98 | 1.19 99 | 1.2.8 100 | 101 | 4.0.rc2 102 | 5.1.1 103 | 3.8.1 104 | 105 | 3.1.2 106 | 3.0.0-M1 107 | 3.0.0-M3 108 | 109 | 3.2.0 110 | 3.0.0-M1 111 | 3.2.0 112 | 3.2.0 113 | 3.0.0-M1 114 | 3.2.4 115 | 3.2.1 116 | 3.0.0-M5 117 | 1.6.8 118 | 119 | 120 | 121 | 122 | 123 | 124 | io.zipkin.brave 125 | brave-bom 126 | ${brave.version} 127 | pom 128 | import 129 | 130 | 131 | 132 | 133 | 134 | 136 | 137 | 138 | 139 | io.zipkin.brave 140 | brave-instrumentation-kafka-clients 141 | 142 | 143 | io.zipkin.reporter2 144 | zipkin-reporter-brave 145 | 146 | 147 | 148 | io.zipkin.reporter2 149 | zipkin-sender-okhttp3 150 | 151 | 152 | io.zipkin.reporter2 153 | zipkin-sender-kafka 154 | 155 | 156 | 157 | 158 | org.apache.kafka 159 | kafka-clients 160 | ${kafka.version} 161 | provided 162 | 163 | 164 | 165 | io.zipkin.brave 166 | brave-tests 167 | test 168 | 169 | 170 | org.junit.jupiter 171 | junit-jupiter 172 | ${junit-jupiter.version} 173 | test 174 | 175 | 176 | org.assertj 177 | assertj-core 178 | ${assertj.version} 179 | test 180 | 181 | 182 | 183 | org.apache.logging.log4j 184 | log4j-jul 185 | ${log4j.version} 186 | test 187 | 188 | 189 | 190 | org.apache.logging.log4j 191 | log4j-1.2-api 192 | ${log4j.version} 193 | test 194 | 195 | 196 | 197 | org.apache.logging.log4j 198 | log4j-slf4j-impl 199 | ${log4j.version} 200 | test 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | io.takari 210 | maven 211 | 0.7.7 212 | 213 | 3.6.3 214 | 215 | 216 | 217 | 218 | 219 | de.qaware.maven 220 | go-offline-maven-plugin 221 | ${go-offline-maven-plugin.version} 222 | 223 | 224 | 225 | 226 | org.codehaus.mojo.signature 227 | ${main.signature.artifact} 228 | 1.0 229 | signature 230 | MAIN 231 | 232 | 233 | com.mycila 234 | license-maven-plugin-git 235 | ${license-maven-plugin.version} 236 | MAIN 237 | 238 | 239 | com.google.errorprone 240 | error_prone_core 241 | ${errorprone.version} 242 | MAIN 243 | 244 | 245 | org.apache.maven.surefire 246 | surefire-junit-platform 247 | ${maven-surefire-plugin.version} 248 | PLUGIN 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | maven-deploy-plugin 257 | ${maven-deploy-plugin.version} 258 | 259 | 260 | 261 | maven-install-plugin 262 | ${maven-install-plugin.version} 263 | 264 | 265 | 266 | maven-jar-plugin 267 | ${maven-jar-plugin.version} 268 | 269 | 270 | 271 | false 272 | 273 | 274 | 275 | 276 | 277 | maven-release-plugin 278 | ${maven-release-plugin.version} 279 | 280 | false 281 | release 282 | true 283 | @{project.version} 284 | 285 | 286 | 287 | 288 | org.sonatype.plugins 289 | nexus-staging-maven-plugin 290 | ${nexus-staging-maven-plugin.version} 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | maven-dependency-plugin 299 | ${maven-dependency-plugin.version} 300 | 301 | 302 | maven-help-plugin 303 | ${maven-help-plugin.version} 304 | 305 | 306 | 307 | maven-compiler-plugin 308 | ${maven-compiler-plugin.version} 309 | true 310 | 311 | 1.8 312 | 1.8 313 | true 314 | true 315 | 316 | 317 | 318 | 319 | maven-surefire-plugin 320 | ${maven-surefire-plugin.version} 321 | 322 | 323 | 324 | 325 | org.apache.logging.log4j.jul.LogManager 326 | 327 | 328 | 329 | 330 | 331 | 332 | org.codehaus.mojo 333 | animal-sniffer-maven-plugin 334 | ${animal-sniffer-maven-plugin.version} 335 | 336 | false 337 | ${skipTests} 338 | 339 | org.codehaus.mojo.signature 340 | ${main.signature.artifact} 341 | 1.0 342 | 343 | 344 | 345 | 346 | 347 | check 348 | 349 | 350 | 351 | 352 | 353 | 354 | maven-enforcer-plugin 355 | ${maven-enforcer-plugin.version} 356 | 357 | 358 | enforce-java 359 | 360 | enforce 361 | 362 | 363 | 364 | 365 | [11,16) 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | com.mycila 375 | license-maven-plugin 376 | ${license-maven-plugin.version} 377 | 378 | ${license.skip} 379 |
${main.basedir}/src/etc/header.txt
380 | 381 | 382 | SLASHSTAR_STYLE 383 | 384 | SCRIPT_STYLE 385 | 386 | SCRIPT_STYLE 387 | SCRIPT_STYLE 388 | 389 | SCRIPT_STYLE 390 | 391 | SCRIPT_STYLE 392 | SCRIPT_STYLE 393 | SCRIPT_STYLE 394 | SCRIPT_STYLE 395 | SCRIPT_STYLE 396 | SCRIPT_STYLE 397 | 398 | 399 | .docker.env 400 | .gitignore 401 | .editorconfig 402 | .mvn/** 403 | mvnw* 404 | etc/header.txt 405 | **/.idea/** 406 | LICENSE 407 | **/*.md 408 | src/test/resources/** 409 | src/main/resources/** 410 | **/*.puml 411 | Makefile 412 | .dockerignore 413 | build-bin/* 414 | 415 | true 416 |
417 | 418 | 419 | com.mycila 420 | license-maven-plugin-git 421 | ${license-maven-plugin.version} 422 | 423 | 424 | 425 | 426 | 427 | check 428 | 429 | compile 430 | 431 | 432 |
433 |
434 | 435 | 436 | 437 | 438 | false 439 | ${main.basedir} 440 | META-INF/ 441 | 442 | LICENSE 443 | NOTICE 444 | 445 | 446 | 447 |
448 | 449 | 450 | 451 | error-prone 452 | 453 | true 454 | 455 | 456 | 457 | 458 | maven-compiler-plugin 459 | 460 | 461 | 462 | default-compile 463 | compile 464 | 465 | compile 466 | 467 | 468 | true 469 | 470 | -XDcompilePolicy=simple 471 | -Xplugin:ErrorProne ${errorprone.args} 472 | 473 | 474 | 475 | com.google.errorprone 476 | error_prone_core 477 | ${errorprone.version} 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | release 490 | 491 | 492 | 493 | org.sonatype.plugins 494 | nexus-staging-maven-plugin 495 | true 496 | 497 | ossrh 498 | https://oss.sonatype.org/ 499 | 501 | 10 502 | true 503 | 504 | 505 | 506 | 507 | org.apache.maven.plugins 508 | maven-gpg-plugin 509 | 1.6 510 | 511 | 512 | sign-artifacts 513 | verify 514 | 515 | sign 516 | 517 | 518 | 519 | --pinentry-mode 520 | loopback 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | maven-source-plugin 530 | ${maven-source-plugin.version} 531 | 532 | 533 | attach-sources 534 | 535 | jar 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | maven-javadoc-plugin 544 | ${maven-javadoc-plugin.version} 545 | 546 | 547 | **/internal/*.java 548 | **/Internal*.java 549 | 550 | *.internal.* 551 | false 552 | 553 | none 554 | 555 | 8 556 | 557 | 558 | 559 | attach-javadocs 560 | 561 | jar 562 | 563 | package 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 |
572 | -------------------------------------------------------------------------------- /src/etc/header.txt: -------------------------------------------------------------------------------- 1 | Copyright ${license.git.copyrightYears} The OpenZipkin 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 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/KafkaInterceptorPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2019 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.propagation.Propagation.Getter; 17 | import brave.propagation.Propagation.Setter; 18 | import java.nio.charset.Charset; 19 | import java.nio.charset.StandardCharsets; 20 | import org.apache.kafka.common.header.Header; 21 | import org.apache.kafka.common.header.Headers; 22 | 23 | /** 24 | * Propagation utilities to inject and extract context from {@link Header} 25 | */ 26 | final class KafkaInterceptorPropagation { 27 | static final Charset UTF_8 = StandardCharsets.UTF_8; 28 | 29 | static final Setter HEADER_SETTER = (carrier, key, value) -> { 30 | carrier.remove(key); 31 | carrier.add(key, value.getBytes(UTF_8)); 32 | }; 33 | 34 | static final Getter HEADER_GETTER = (carrier, key) -> { 35 | Header header = carrier.lastHeader(key); 36 | if (header == null) return null; 37 | return new String(header.value(), UTF_8); 38 | }; 39 | 40 | KafkaInterceptorPropagation() { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/KafkaInterceptorTagKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2019 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | /** 17 | * Keys to be tagged on spans created by interceptors. See {@link TracingConsumerInterceptor} and 18 | * {@link TracingProducerInterceptor} 19 | */ 20 | class KafkaInterceptorTagKey { 21 | static final String KAFKA_TOPIC = "kafka.topic"; 22 | static final String KAFKA_KEY = "kafka.key"; 23 | static final String KAFKA_CLIENT_ID = "kafka.client.id"; 24 | static final String KAFKA_GROUP_ID = "kafka.group.id"; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/TracingBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.Tracing; 17 | import brave.sampler.Sampler; 18 | import org.apache.kafka.clients.CommonClientConfigs; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import zipkin2.codec.Encoding; 22 | import zipkin2.reporter.Sender; 23 | import zipkin2.reporter.brave.AsyncZipkinSpanHandler; 24 | import zipkin2.reporter.kafka.KafkaSender; 25 | import zipkin2.reporter.okhttp3.OkHttpSender; 26 | 27 | import static brave.kafka.interceptor.TracingConfiguration.ENCODING_CONFIG; 28 | import static brave.kafka.interceptor.TracingConfiguration.ENCODING_DEFAULT; 29 | import static brave.kafka.interceptor.TracingConfiguration.HTTP_ENDPOINT_CONFIG; 30 | import static brave.kafka.interceptor.TracingConfiguration.HTTP_ENDPOINT_DEFAULT; 31 | import static brave.kafka.interceptor.TracingConfiguration.KAFKA_BOOTSTRAP_SERVERS_CONFIG; 32 | import static brave.kafka.interceptor.TracingConfiguration.LOCAL_SERVICE_NAME_CONFIG; 33 | import static brave.kafka.interceptor.TracingConfiguration.LOCAL_SERVICE_NAME_DEFAULT; 34 | import static brave.kafka.interceptor.TracingConfiguration.SAMPLER_RATE_CONFIG; 35 | import static brave.kafka.interceptor.TracingConfiguration.SAMPLER_RATE_DEFAULT; 36 | import static brave.kafka.interceptor.TracingConfiguration.SENDER_TYPE_CONFIG; 37 | import static brave.kafka.interceptor.TracingConfiguration.SENDER_TYPE_DEFAULT; 38 | import static brave.kafka.interceptor.TracingConfiguration.TRACE_ID_128BIT_ENABLED_CONFIG; 39 | import static brave.kafka.interceptor.TracingConfiguration.TRACE_ID_128BIT_ENABLED_DEFAULT; 40 | 41 | import java.util.HashMap; 42 | import java.util.Map; 43 | 44 | /** 45 | * Initialization of Zipkin Tracing components. 46 | */ 47 | class TracingBuilder { 48 | static final Logger LOGGER = LoggerFactory.getLogger(TracingBuilder.class); 49 | 50 | final String localServiceName; 51 | final boolean traceId128Bit; 52 | final TracingConfiguration configuration; 53 | 54 | TracingBuilder(TracingConfiguration configuration) { 55 | this.configuration = configuration; 56 | this.localServiceName = 57 | configuration.getStringOrDefault(LOCAL_SERVICE_NAME_CONFIG, LOCAL_SERVICE_NAME_DEFAULT); 58 | String traceIdEnabledValue = configuration.getStringOrDefault(TRACE_ID_128BIT_ENABLED_CONFIG, 59 | TRACE_ID_128BIT_ENABLED_DEFAULT); 60 | this.traceId128Bit = Boolean.parseBoolean(traceIdEnabledValue); 61 | } 62 | 63 | Tracing build() { 64 | Tracing.Builder builder = Tracing.newBuilder(); 65 | Sender sender = new SenderBuilder(configuration).build(); 66 | if (sender != null) { 67 | // TODO: close hook for both sender and handler? 68 | AsyncZipkinSpanHandler zipkinSpanHandler = AsyncZipkinSpanHandler.create(sender); 69 | builder.addSpanHandler(zipkinSpanHandler); 70 | } 71 | Sampler sampler = new SamplerBuilder(configuration).build(); 72 | return builder.sampler(sampler) 73 | .localServiceName(localServiceName) 74 | .traceId128Bit(traceId128Bit) 75 | .build(); 76 | } 77 | 78 | static class SenderBuilder { 79 | final SenderType senderType; 80 | final TracingConfiguration configuration; 81 | 82 | SenderBuilder(TracingConfiguration configuration) { 83 | String senderTypeValue = 84 | configuration.getStringOrDefault(SENDER_TYPE_CONFIG, SENDER_TYPE_DEFAULT); 85 | this.senderType = SenderType.valueOf(senderTypeValue); 86 | this.configuration = configuration; 87 | } 88 | 89 | Sender build() { 90 | Encoding encoding = new EncodingBuilder(configuration).build(); 91 | switch (senderType) { 92 | case HTTP: 93 | return new HttpSenderBuilder(configuration).build(encoding); 94 | case KAFKA: 95 | return new KafkaSenderBuilder(configuration).build(encoding); 96 | case NONE: 97 | return null; 98 | default: 99 | throw new IllegalArgumentException("Zipkin sender type unknown"); 100 | } 101 | } 102 | 103 | enum SenderType { 104 | NONE, HTTP, KAFKA 105 | } 106 | } 107 | 108 | static class HttpSenderBuilder { 109 | final String endpoint; 110 | 111 | HttpSenderBuilder(TracingConfiguration configuration) { 112 | this.endpoint = configuration.getStringOrDefault(HTTP_ENDPOINT_CONFIG, HTTP_ENDPOINT_DEFAULT); 113 | } 114 | 115 | Sender build(Encoding encoding) { 116 | return OkHttpSender.newBuilder().endpoint(endpoint).encoding(encoding).build(); 117 | } 118 | } 119 | 120 | public static class KafkaSenderBuilder { 121 | 122 | final String bootstrapServers; 123 | final Map overrides = new HashMap<>(); 124 | 125 | KafkaSenderBuilder(TracingConfiguration configuration) { 126 | this.bootstrapServers = configuration.getStringOrDefault( 127 | KAFKA_BOOTSTRAP_SERVERS_CONFIG, 128 | configuration.getStringOrDefault(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, 129 | configuration.getStringList(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG))); 130 | 131 | this.overrides.putAll(configuration.getKafkaOverrides()); 132 | } 133 | 134 | Sender build(Encoding encoding) { 135 | return KafkaSender.newBuilder().bootstrapServers(bootstrapServers).overrides(overrides).encoding(encoding).build(); 136 | } 137 | } 138 | 139 | static class EncodingBuilder { 140 | final Encoding encoding; 141 | 142 | EncodingBuilder(TracingConfiguration configuration) { 143 | String encodingValue = configuration.getStringOrDefault(ENCODING_CONFIG, ENCODING_DEFAULT); 144 | encoding = Encoding.valueOf(encodingValue); 145 | } 146 | 147 | Encoding build() { 148 | return encoding; 149 | } 150 | } 151 | 152 | static class SamplerBuilder { 153 | static final Float SAMPLER_RATE_FALLBACK = 0.0F; 154 | 155 | final Float rate; 156 | 157 | SamplerBuilder(TracingConfiguration configuration) { 158 | String rateValue = 159 | configuration.getStringOrDefault(SAMPLER_RATE_CONFIG, SAMPLER_RATE_DEFAULT); 160 | Float rate = Float.valueOf(rateValue); 161 | if (rate > 1.0 || rate <= 0.0 || rate.isNaN()) { 162 | rate = SAMPLER_RATE_FALLBACK; 163 | LOGGER.warn( 164 | "Invalid sampler rate {}, must be between 0 and 1. Falling back to {}", 165 | rate, SAMPLER_RATE_FALLBACK); 166 | } 167 | this.rate = rate; 168 | } 169 | 170 | Sampler build() { 171 | return Sampler.create(rate); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/TracingConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import java.util.AbstractList; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * Tracing Configuration wraps properties provided by a Kafka Client and enable access to 26 | * configuration values. 27 | */ 28 | public class TracingConfiguration { 29 | static final Logger LOGGER = LoggerFactory.getLogger(TracingConfiguration.class); 30 | 31 | public static final String SENDER_TYPE_CONFIG = "zipkin.sender.type"; 32 | public static final String SENDER_TYPE_DEFAULT = "NONE"; 33 | public static final String HTTP_ENDPOINT_CONFIG = "zipkin.http.endpoint"; 34 | public static final String HTTP_ENDPOINT_DEFAULT = "http://localhost:9411/api/v2/spans"; 35 | public static final String KAFKA_BOOTSTRAP_SERVERS_CONFIG = "zipkin.kafka.bootstrap.servers"; 36 | public static final String LOCAL_SERVICE_NAME_CONFIG = "zipkin.local.service.name"; 37 | public static final String LOCAL_SERVICE_NAME_DEFAULT = "kafka-client"; 38 | public static final String REMOTE_SERVICE_NAME_CONFIG = "zipkin.remote.service.name"; 39 | public static final String REMOTE_SERVICE_NAME_DEFAULT = "kafka"; 40 | public static final String TRACE_ID_128BIT_ENABLED_CONFIG = "zipkin.trace.id.128bit.enabled"; 41 | public static final String TRACE_ID_128BIT_ENABLED_DEFAULT = "true"; 42 | public static final String ENCODING_CONFIG = "zipkin.encoding"; 43 | public static final String ENCODING_DEFAULT = "JSON"; 44 | public static final String SAMPLER_RATE_CONFIG = "zipkin.sampler.rate"; 45 | public static final String SAMPLER_RATE_DEFAULT = "1.0F"; 46 | public static final String KAFKA_OVERRIDE_PREFIX = "zipkin.kafka."; 47 | 48 | final Map configs; 49 | 50 | TracingConfiguration(Map configs) { 51 | this.configs = configs; 52 | } 53 | 54 | String getStringList(String configKey) { 55 | final String value; 56 | final Object valueObject = configs.get(configKey); 57 | if (valueObject instanceof AbstractList) { 58 | AbstractList valueList = (AbstractList) valueObject; 59 | value = String.join(",", valueList); 60 | } else { 61 | LOGGER.warn("{} of type ArrayList is not found in properties", configKey); 62 | value = null; 63 | } 64 | return value; 65 | } 66 | 67 | /** 68 | * @return Value as String. If not found, then null is returned. 69 | */ 70 | String getStringOrDefault(String configKey, String defaultValue) { 71 | final String value; 72 | final Object valueObject = configs.get(configKey); 73 | if (valueObject instanceof String) { 74 | value = (String) valueObject; 75 | } else { 76 | LOGGER.warn("{} of type String is not found in properties", configKey); 77 | value = defaultValue; 78 | } 79 | return value; 80 | } 81 | 82 | String getString(String configKey) { 83 | return getStringOrDefault(configKey, null); 84 | } 85 | 86 | /** 87 | * @return Value as a string regardless of whether the type of the property is a String 88 | * or a List (for instance `bootstrap.servers` property may have a List of servers 89 | * instead of a single String). If not found, then null is returned. 90 | */ 91 | String getStringOrStringList(String configKey) { 92 | final String value; 93 | final Object valueObject = configs.get(configKey); 94 | if (valueObject instanceof AbstractList) { 95 | value = getStringList(configKey); 96 | } else { 97 | value = getStringOrDefault(configKey, null); 98 | } 99 | return value; 100 | } 101 | 102 | Map getKafkaOverrides() { 103 | Map overrides = new HashMap<>(); 104 | 105 | for (String key : getKeySet()) { 106 | if (!key.equals(KAFKA_BOOTSTRAP_SERVERS_CONFIG) && key.startsWith(KAFKA_OVERRIDE_PREFIX)) 107 | copyConfig(overrides, key); 108 | } 109 | 110 | return overrides; 111 | } 112 | 113 | void copyConfig(Map to, String key) { 114 | String value = getStringOrStringList(key); 115 | String kafkaKey = key.replace(KAFKA_OVERRIDE_PREFIX,""); 116 | if (value != null && value.length() > 0) { 117 | to.put(kafkaKey, value); 118 | LOGGER.info("Adding '{}:{}' property to kafka configuration", kafkaKey, value); 119 | } 120 | } 121 | 122 | Set getKeySet() { 123 | return configs.keySet(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/TracingConsumerInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2019 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.Span; 17 | import brave.Tracing; 18 | import brave.propagation.TraceContext; 19 | import brave.propagation.TraceContextOrSamplingFlags; 20 | import java.util.LinkedHashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import org.apache.kafka.clients.consumer.ConsumerConfig; 24 | import org.apache.kafka.clients.consumer.ConsumerInterceptor; 25 | import org.apache.kafka.clients.consumer.ConsumerRecord; 26 | import org.apache.kafka.clients.consumer.ConsumerRecords; 27 | import org.apache.kafka.clients.consumer.OffsetAndMetadata; 28 | import org.apache.kafka.common.TopicPartition; 29 | import org.apache.kafka.common.header.Headers; 30 | 31 | import static brave.kafka.interceptor.TracingConfiguration.REMOTE_SERVICE_NAME_CONFIG; 32 | import static brave.kafka.interceptor.TracingConfiguration.REMOTE_SERVICE_NAME_DEFAULT; 33 | 34 | /** 35 | * Record spans when records are received from Consumer API. 36 | *

37 | * Creates a span per Record, and link it with an incoming context if stored in Records header. 38 | */ 39 | public class TracingConsumerInterceptor implements ConsumerInterceptor { 40 | static final String SPAN_NAME = "poll"; 41 | 42 | TracingConfiguration configuration; 43 | Tracing tracing; 44 | String remoteServiceName; 45 | TraceContext.Injector injector; 46 | TraceContext.Extractor extractor; 47 | 48 | @Override public ConsumerRecords onConsume(ConsumerRecords records) { 49 | if (records.isEmpty() || tracing.isNoop()) return records; 50 | Map consumerSpansForTopic = new LinkedHashMap<>(); 51 | for (TopicPartition partition : records.partitions()) { 52 | String topic = partition.topic(); 53 | List> recordsInPartition = records.records(partition); 54 | for (ConsumerRecord record : recordsInPartition) { 55 | TraceContextOrSamplingFlags extracted = extractor.extract(record.headers()); 56 | // If we extracted neither a trace context, nor request-scoped data 57 | // (extra), 58 | // make or reuse a span for this topic 59 | if (extracted.samplingFlags() != null && extracted.extra().isEmpty()) { 60 | Span consumerSpanForTopic = consumerSpansForTopic.get(topic); 61 | if (consumerSpanForTopic == null) { 62 | consumerSpansForTopic.put(topic, 63 | consumerSpanForTopic = tracing.tracer() 64 | .nextSpan(extracted) 65 | .name(SPAN_NAME) 66 | .kind(Span.Kind.CONSUMER) 67 | .remoteServiceName(remoteServiceName) 68 | .tag(KafkaInterceptorTagKey.KAFKA_TOPIC, topic) 69 | .tag(KafkaInterceptorTagKey.KAFKA_GROUP_ID, 70 | configuration.getString(ConsumerConfig.GROUP_ID_CONFIG)) 71 | .tag(KafkaInterceptorTagKey.KAFKA_CLIENT_ID, 72 | configuration.getString(ConsumerConfig.CLIENT_ID_CONFIG)) 73 | .start()); 74 | } 75 | // no need to remove propagation headers as we failed to extract 76 | // anything 77 | injector.inject(consumerSpanForTopic.context(), record.headers()); 78 | } else { // we extracted request-scoped data, so cannot share a consumer 79 | // span. 80 | Span span = tracing.tracer().nextSpan(extracted); 81 | if (!span.isNoop()) { 82 | span.name(SPAN_NAME) 83 | .kind(Span.Kind.CONSUMER) 84 | .remoteServiceName(remoteServiceName) 85 | .tag(KafkaInterceptorTagKey.KAFKA_TOPIC, topic) 86 | .tag(KafkaInterceptorTagKey.KAFKA_GROUP_ID, 87 | configuration.getString(ConsumerConfig.GROUP_ID_CONFIG)) 88 | .tag(KafkaInterceptorTagKey.KAFKA_CLIENT_ID, 89 | configuration.getString(ConsumerConfig.CLIENT_ID_CONFIG)) 90 | .start() 91 | .finish(); // span won't be shared by other records 92 | } 93 | // remove prior propagation headers from the record 94 | tracing.propagation().keys().forEach(key -> record.headers().remove(key)); 95 | injector.inject(span.context(), record.headers()); 96 | } 97 | } 98 | } 99 | consumerSpansForTopic.values().forEach(Span::finish); 100 | return records; 101 | } 102 | 103 | @Override public void onCommit(Map map) { 104 | // Do nothing 105 | } 106 | 107 | @Override public void close() { 108 | tracing.close(); 109 | } 110 | 111 | @Override public void configure(Map configs) { 112 | configuration = new TracingConfiguration(configs); 113 | remoteServiceName = 114 | configuration.getStringOrDefault(REMOTE_SERVICE_NAME_CONFIG, REMOTE_SERVICE_NAME_DEFAULT); 115 | tracing = new TracingBuilder(configuration).build(); 116 | extractor = tracing.propagation().extractor(KafkaInterceptorPropagation.HEADER_GETTER); 117 | injector = tracing.propagation().injector(KafkaInterceptorPropagation.HEADER_SETTER); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/brave/kafka/interceptor/TracingProducerInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2019 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.Span; 17 | import brave.Tracing; 18 | import brave.propagation.TraceContext; 19 | import brave.propagation.TraceContextOrSamplingFlags; 20 | import java.util.Map; 21 | import org.apache.kafka.clients.producer.ProducerConfig; 22 | import org.apache.kafka.clients.producer.ProducerInterceptor; 23 | import org.apache.kafka.clients.producer.ProducerRecord; 24 | import org.apache.kafka.clients.producer.RecordMetadata; 25 | import org.apache.kafka.common.header.Headers; 26 | 27 | /** 28 | * Record traces when records are sent to a Kafka Topic. 29 | *

30 | * Extract context from incoming Record, if exist injected in its header, and use it to link it to 31 | * the Span created by the interceptor. 32 | */ 33 | public class TracingProducerInterceptor implements ProducerInterceptor { 34 | static final String SPAN_NAME = "send"; 35 | 36 | TracingConfiguration configuration; 37 | Tracing tracing; 38 | String remoteServiceName; 39 | TraceContext.Injector injector; 40 | TraceContext.Extractor extractor; 41 | 42 | @Override public ProducerRecord onSend(ProducerRecord record) { 43 | TraceContextOrSamplingFlags traceContextOrSamplingFlags = extractor.extract(record.headers()); 44 | Span span = tracing.tracer().nextSpan(traceContextOrSamplingFlags); 45 | tracing.propagation().keys().forEach(key -> record.headers().remove(key)); 46 | injector.inject(span.context(), record.headers()); 47 | if (!span.isNoop()) { 48 | if (record.key() instanceof String && !"".equals(record.key())) { 49 | span.tag(KafkaInterceptorTagKey.KAFKA_KEY, record.key().toString()); 50 | } 51 | span 52 | .tag(KafkaInterceptorTagKey.KAFKA_TOPIC, record.topic()) 53 | .tag(KafkaInterceptorTagKey.KAFKA_CLIENT_ID, 54 | configuration.getString(ProducerConfig.CLIENT_ID_CONFIG)) 55 | .name(SPAN_NAME) 56 | .kind(Span.Kind.PRODUCER) 57 | .remoteServiceName(remoteServiceName) 58 | .start() 59 | .finish(); 60 | } 61 | return record; 62 | } 63 | 64 | @Override public void onAcknowledgement(RecordMetadata recordMetadata, Exception exception) { 65 | // Do nothing 66 | } 67 | 68 | @Override public void close() { 69 | tracing.close(); 70 | } 71 | 72 | @Override public void configure(Map configs) { 73 | configuration = new TracingConfiguration(configs); 74 | remoteServiceName = 75 | configuration.getStringOrDefault(TracingConfiguration.REMOTE_SERVICE_NAME_CONFIG, 76 | TracingConfiguration.REMOTE_SERVICE_NAME_DEFAULT); 77 | tracing = new TracingBuilder(configuration).build(); 78 | extractor = tracing.propagation().extractor(KafkaInterceptorPropagation.HEADER_GETTER); 79 | injector = tracing.propagation().injector(KafkaInterceptorPropagation.HEADER_SETTER); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/brave/kafka/interceptor/BaseTracingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2020 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.Tracing; 17 | import brave.test.TestSpanHandler; 18 | import java.util.HashMap; 19 | 20 | class BaseTracingTest { 21 | TestSpanHandler spans = new TestSpanHandler(); 22 | Tracing tracing = Tracing.newBuilder().addSpanHandler(spans).build(); 23 | HashMap map = new HashMap<>(); 24 | 25 | BaseTracingTest() { 26 | map.put("client.id", "client-1"); 27 | map.put("group.id", "group-1"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/brave/kafka/interceptor/TracingBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import brave.sampler.Sampler; 17 | import java.util.Arrays; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import org.apache.kafka.clients.CommonClientConfigs; 21 | import org.junit.jupiter.api.Test; 22 | import zipkin2.codec.Encoding; 23 | import zipkin2.reporter.Sender; 24 | import zipkin2.reporter.kafka.KafkaSender; 25 | import zipkin2.reporter.okhttp3.OkHttpSender; 26 | 27 | import static brave.kafka.interceptor.TracingConfiguration.ENCODING_CONFIG; 28 | import static brave.kafka.interceptor.TracingConfiguration.ENCODING_DEFAULT; 29 | import static brave.kafka.interceptor.TracingConfiguration.KAFKA_BOOTSTRAP_SERVERS_CONFIG; 30 | import static brave.kafka.interceptor.TracingConfiguration.SAMPLER_RATE_CONFIG; 31 | import static brave.kafka.interceptor.TracingConfiguration.SAMPLER_RATE_DEFAULT; 32 | import static brave.kafka.interceptor.TracingConfiguration.SENDER_TYPE_CONFIG; 33 | import static org.assertj.core.api.Assertions.assertThat; 34 | 35 | class TracingBuilderTest { 36 | 37 | @Test void shouldBuildDefaultEncoding() { 38 | // Given 39 | Map map = new HashMap<>(); 40 | TracingConfiguration config = new TracingConfiguration(map); 41 | // When 42 | Encoding encoding = new TracingBuilder.EncodingBuilder(config).build(); 43 | // Then 44 | assertThat(encoding).isEqualTo(Encoding.valueOf(ENCODING_DEFAULT)); 45 | } 46 | 47 | @Test void shouldBuildEncoding() { 48 | // Given 49 | Map map = new HashMap<>(); 50 | map.put(ENCODING_CONFIG, Encoding.PROTO3.name()); 51 | TracingConfiguration config = new TracingConfiguration(map); 52 | // When 53 | Encoding encoding = new TracingBuilder.EncodingBuilder(config).build(); 54 | // Then 55 | assertThat(encoding).isEqualTo(Encoding.PROTO3); 56 | } 57 | 58 | @Test void shouldBuildDefaultSampler() { 59 | // Given 60 | Map map = new HashMap<>(); 61 | TracingConfiguration config = new TracingConfiguration(map); 62 | // When 63 | Sampler sampler = new TracingBuilder.SamplerBuilder(config).build(); 64 | // Then 65 | float defaultSampler = Float.parseFloat(SAMPLER_RATE_DEFAULT); 66 | assertThat(sampler).isEqualTo(Sampler.create(defaultSampler)); 67 | } 68 | 69 | @Test void shouldBuildSampler() { 70 | // Given 71 | Map map = new HashMap<>(); 72 | map.put(SAMPLER_RATE_CONFIG, "0.5"); 73 | TracingConfiguration config = new TracingConfiguration(map); 74 | // When 75 | Sampler sampler = new TracingBuilder.SamplerBuilder(config).build(); 76 | // Then 77 | assertThat(sampler).isNotNull(); 78 | } 79 | 80 | @Test void shouldBuildSamplerWithFallback() { 81 | // Given 82 | Map map = new HashMap<>(); 83 | map.put(SAMPLER_RATE_CONFIG, "1.5"); 84 | TracingConfiguration config = new TracingConfiguration(map); 85 | // When 86 | Sampler sampler = new TracingBuilder.SamplerBuilder(config).build(); 87 | // Then 88 | assertThat(sampler).isNotNull(); 89 | } 90 | 91 | @Test void shouldBuildNullSender() { 92 | // Given 93 | Map map = new HashMap<>(); 94 | TracingConfiguration config = new TracingConfiguration(map); 95 | // When 96 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 97 | // Then 98 | assertThat(sender).isNull(); 99 | } 100 | 101 | @Test void shouldBuildNoneSender() { 102 | // Given 103 | Map map = new HashMap<>(); 104 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.NONE.name()); 105 | TracingConfiguration config = new TracingConfiguration(map); 106 | // When 107 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 108 | // Then 109 | assertThat(sender).isNull(); 110 | } 111 | 112 | @Test void shouldBuildHttpSender() { 113 | // Given 114 | Map map = new HashMap<>(); 115 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.HTTP.name()); 116 | TracingConfiguration config = new TracingConfiguration(map); 117 | // When 118 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 119 | // Then 120 | assertThat(sender).isInstanceOf(OkHttpSender.class); 121 | } 122 | 123 | @Test void shouldBuildKafkaSenderWithConfig() { 124 | // Given 125 | Map map = new HashMap<>(); 126 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.KAFKA.name()); 127 | map.put(KAFKA_BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); 128 | TracingConfiguration config = new TracingConfiguration(map); 129 | // When 130 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 131 | // Then 132 | assertThat(sender).isInstanceOf(KafkaSender.class); 133 | } 134 | 135 | @Test void shouldBuildKafkaSenderWithDefault() { 136 | // Given 137 | Map map = new HashMap<>(); 138 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.KAFKA.name()); 139 | map.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); 140 | TracingConfiguration config = new TracingConfiguration(map); 141 | // When 142 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 143 | // Then 144 | assertThat(sender).isInstanceOf(KafkaSender.class); 145 | } 146 | 147 | @Test void shouldBuildKafkaSenderWithList() { 148 | // Given 149 | Map map = new HashMap<>(); 150 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.KAFKA.name()); 151 | map.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, 152 | Arrays.asList("localhost:9092", "localhost:9094")); 153 | TracingConfiguration config = new TracingConfiguration(map); 154 | // When 155 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 156 | // Then 157 | assertThat(sender).isInstanceOf(KafkaSender.class); 158 | } 159 | 160 | 161 | @Test void shouldBuildKafkaSenderWithOverrides() { 162 | // Given 163 | Map map = new HashMap<>(); 164 | map.put(SENDER_TYPE_CONFIG, TracingBuilder.SenderBuilder.SenderType.KAFKA.name()); 165 | map.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); 166 | map.put(TracingConfiguration.KAFKA_OVERRIDE_PREFIX + "acks", "all"); 167 | TracingConfiguration config = new TracingConfiguration(map); 168 | // When 169 | Sender sender = new TracingBuilder.SenderBuilder(config).build(); 170 | // Then 171 | assertThat(sender).isInstanceOf(KafkaSender.class); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/test/java/brave/kafka/interceptor/TracingConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.assertj.core.api.Assertions.assertThat; 23 | 24 | class TracingConfigurationTest { 25 | 26 | @Test void shouldGetStringWhenValueExists() { 27 | // Given 28 | Map configs = new HashMap<>(); 29 | configs.put("k", "v"); 30 | // When 31 | TracingConfiguration config = new TracingConfiguration(configs); 32 | // Then 33 | assertThat(config.getString("k")).isEqualTo("v"); 34 | } 35 | 36 | @Test void shouldGetNullStringWhenValueDoesNotExist() { 37 | // Given 38 | Map configs = new HashMap<>(); 39 | // When 40 | TracingConfiguration config = new TracingConfiguration(configs); 41 | // Then 42 | assertThat(config.getString("k1")).isNull(); 43 | } 44 | 45 | @Test void shouldGetDefaultWhenStringDoesNotExist() { 46 | // Given 47 | Map configs = new HashMap<>(); 48 | // When 49 | TracingConfiguration config = new TracingConfiguration(configs); 50 | // Then 51 | assertThat(config.getStringOrDefault("k", "v")).isEqualTo("v"); 52 | } 53 | 54 | @Test void shouldGetStringAndNotDefaultWhenValueExists() { 55 | // Given 56 | Map configs = new HashMap<>(); 57 | configs.put("k", "v"); 58 | // When 59 | TracingConfiguration config = new TracingConfiguration(configs); 60 | // Then 61 | assertThat(config.getStringOrDefault("k", "v1")).isEqualTo("v"); 62 | } 63 | 64 | @Test void shouldGetStringListWhenValueExists() { 65 | // Given 66 | Map> configs = new HashMap<>(); 67 | configs.put("k", Arrays.asList("v", "v1")); 68 | // When 69 | TracingConfiguration config = new TracingConfiguration(configs); 70 | // Then 71 | assertThat(config.getStringList("k")).isEqualTo("v,v1"); 72 | } 73 | 74 | @Test void shouldGetNullWhenStringListValueDoesNotExist() { 75 | // Given 76 | Map> configs = new HashMap<>(); 77 | // When 78 | TracingConfiguration config = new TracingConfiguration(configs); 79 | // Then 80 | assertThat(config.getStringList("k")).isNull(); 81 | } 82 | 83 | @Test void shouldGetAllKeySet() { 84 | // Given 85 | Map configs = new HashMap<>(); 86 | configs.put("k1", "v1"); 87 | configs.put("k2", "v2"); 88 | configs.put("k3", Arrays.asList("v", "v3")); 89 | // When 90 | TracingConfiguration config = new TracingConfiguration(configs); 91 | // Then 92 | assertThat(config.getKeySet()).isEqualTo(configs.keySet()); 93 | } 94 | 95 | @Test void shouldGetStringOrStringList() { 96 | // Given 97 | Map configs = new HashMap<>(); 98 | configs.put("k1", "v1"); 99 | configs.put("k2", Arrays.asList("v", "v2")); 100 | // When 101 | TracingConfiguration config = new TracingConfiguration(configs); 102 | // Then 103 | assertThat(config.getStringOrStringList("k1")).isEqualTo("v1"); 104 | assertThat(config.getStringOrStringList("k2")).isEqualTo("v,v2"); 105 | } 106 | 107 | @Test void shouldGetKafkaOverrides() { 108 | // Given 109 | Map configs = new HashMap<>(); 110 | configs.put(TracingConfiguration.KAFKA_OVERRIDE_PREFIX + "acks", "all"); 111 | // When 112 | TracingConfiguration config = new TracingConfiguration(configs); 113 | // Then 114 | assertThat(config.getKafkaOverrides()).containsEntry("acks", "all"); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/test/java/brave/kafka/interceptor/TracingConsumerInterceptorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2020 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import java.util.Arrays; 17 | import java.util.Collections; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | import org.apache.kafka.clients.consumer.ConsumerRecord; 22 | import org.apache.kafka.clients.consumer.ConsumerRecords; 23 | import org.apache.kafka.common.TopicPartition; 24 | import org.junit.jupiter.api.Test; 25 | 26 | import static org.assertj.core.api.Assertions.assertThat; 27 | 28 | class TracingConsumerInterceptorTest extends BaseTracingTest { 29 | 30 | @Test void shouldNotTouchRecords() { 31 | // Given 32 | Map>> topicPartitionAndRecords = 33 | new HashMap<>(); 34 | ConsumerRecord record = new ConsumerRecord<>("topic", 0, 0L, 35 | "k", "v"); 36 | topicPartitionAndRecords.put(new TopicPartition("topic", 0), 37 | Collections.singletonList(record)); 38 | ConsumerRecords records = new ConsumerRecords<>( 39 | topicPartitionAndRecords); 40 | TracingConsumerInterceptor interceptor = 41 | new TracingConsumerInterceptor<>(); 42 | interceptor.configure(map); 43 | // When 44 | ConsumerRecords tracedRecords = interceptor.onConsume(records); 45 | // Then 46 | assertThat(tracedRecords).isEqualTo(records); 47 | } 48 | 49 | @Test void shouldCreateSpansOnConsume() { 50 | // Given 51 | Map>> topicPartitionAndRecords = 52 | new HashMap<>(); 53 | ConsumerRecord record = new ConsumerRecord<>("topic", 0, 0L, 54 | "k", "v"); 55 | topicPartitionAndRecords.put(new TopicPartition("topic", 0), 56 | Arrays.asList(record, record, record)); 57 | ConsumerRecords records = new ConsumerRecords<>( 58 | topicPartitionAndRecords); 59 | TracingConsumerInterceptor interceptor = 60 | new TracingConsumerInterceptor<>(); 61 | interceptor.configure(map); 62 | interceptor.tracing = tracing; 63 | // When 64 | interceptor.onConsume(records); 65 | // Then 66 | assertThat(spans).hasSize(3); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/brave/kafka/interceptor/TracingProducerInterceptorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2020 The OpenZipkin 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 brave.kafka.interceptor; 15 | 16 | import org.apache.kafka.clients.producer.ProducerRecord; 17 | import org.junit.jupiter.api.Test; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | public class TracingProducerInterceptorTest extends BaseTracingTest { 22 | 23 | ProducerRecord record = new ProducerRecord<>("topic", "value"); 24 | 25 | @Test void shouldNotTouchRecords() { 26 | TracingProducerInterceptor interceptor = new TracingProducerInterceptor<>(); 27 | interceptor.configure(map); 28 | ProducerRecord tracedRecord = interceptor.onSend(record); 29 | assertThat(tracedRecord).isEqualTo(record); 30 | } 31 | 32 | @Test void shouldCreateSpanOnSend() { 33 | // Given 34 | TracingProducerInterceptor interceptor = new TracingProducerInterceptor<>(); 35 | interceptor.configure(map); 36 | interceptor.tracing = tracing; 37 | // When 38 | interceptor.onSend(record); 39 | // Then 40 | assertThat(spans).isNotEmpty(); 41 | } 42 | 43 | @Test void shouldCreateChildSpanIfContextAvailable() { 44 | // Given 45 | TracingProducerInterceptor interceptor = new TracingProducerInterceptor<>(); 46 | interceptor.configure(map); 47 | interceptor.tracing = tracing; 48 | brave.Span span = tracing.tracer().newTrace(); 49 | tracing.propagation().injector(KafkaInterceptorPropagation.HEADER_SETTER) 50 | .inject(span.context(), record.headers()); 51 | // When 52 | interceptor.onSend(record); 53 | // Then 54 | assertThat(spans).hasSize(1); 55 | assertThat(spans.get(0).parentId()).isEqualTo(span.context().spanIdString()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | appenders=console 2 | appender.console.type=Console 3 | appender.console.name=STDOUT 4 | appender.console.layout.type=PatternLayout 5 | appender.console.layout.pattern=%d{ABSOLUTE} %-5p [%t] %C{2} (%F:%L) - %m%n 6 | rootLogger.level=warn 7 | rootLogger.appenderRefs=stdout 8 | rootLogger.appenderRef.stdout.ref=STDOUT 9 | --------------------------------------------------------------------------------