├── .gitignore ├── README.md ├── consumer-app ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── burkaa01 │ │ │ └── consumer │ │ │ ├── ConsumerApplication.java │ │ │ ├── answer │ │ │ └── AnswerProducer.java │ │ │ └── config │ │ │ ├── AnswerProducerConfig.java │ │ │ ├── SentenceConsumerConfig.java │ │ │ └── TracingConfig.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── github │ │ └── burkaa01 │ │ └── consumer │ │ └── ConsumerApplicationTests.java │ └── resources │ └── test.yml ├── docker-compose.yml ├── jaeger-tracing-kafka.png ├── kafka-connect ├── README.md ├── elastic-sink │ └── elastic-sink.json └── file-source │ ├── file-source.json │ └── numbers.txt ├── rest-app ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── burkaa01 │ │ │ └── rest │ │ │ ├── RestApplication.java │ │ │ ├── config │ │ │ └── TracingConfig.java │ │ │ └── controller │ │ │ └── RandomRestController.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── github │ │ └── burkaa01 │ │ └── rest │ │ └── RestApplicationTests.java │ └── resources │ └── test.yml ├── spring-consumer-app ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── burkaa01 │ │ │ └── springconsumer │ │ │ ├── SpringConsumerApplication.java │ │ │ ├── config │ │ │ ├── NumberConsumerConfig.java │ │ │ ├── SentenceProducerConfig.java │ │ │ ├── TracingChildRestTemplateInterceptor.java │ │ │ └── TracingConfig.java │ │ │ └── sentence │ │ │ └── SentenceProducer.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── github │ │ └── burkaa01 │ │ └── springconsumer │ │ └── SpringConsumerApplicationTests.java │ └── resources │ └── test.yml ├── stream-app ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── burkaa01 │ │ │ └── stream │ │ │ ├── StreamApplication.java │ │ │ ├── config │ │ │ ├── DeadLetterProducerConfig.java │ │ │ ├── DividerStreamsConfig.java │ │ │ └── TracingConfig.java │ │ │ └── divider │ │ │ ├── DividerMapper.java │ │ │ ├── DividerStream.java │ │ │ └── ValueWithHeaders.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── github │ │ └── burkaa01 │ │ └── stream │ │ └── StreamApplicationTests.java │ └── resources │ └── test.yml └── topic-configuration ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── github │ │ └── burkaa01 │ │ └── topic │ │ ├── TopicConfigurationApplication.java │ │ └── config │ │ └── TopicConfiguration.java └── resources │ └── application.yml └── test ├── java └── com │ └── github │ └── burkaa01 │ └── topic │ └── TopicConfigurationApplicationTests.java └── resources └── test.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jaeger-tracing-kafka 2 | 3 | ![alt text](jaeger-tracing-kafka.png) 4 | 5 | This is an example of a Kafka project with Jaeger tracing. 6 | -------------------------------------------------------------------------------- /consumer-app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /consumer-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | COPY build/libs/consumer-app-0.0.1-SNAPSHOT.jar /app.jar 4 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /consumer-app/README.md: -------------------------------------------------------------------------------- 1 | # consumer-app 2 | 3 | This is an example of a Kafka consumer and producer application with Jaeger tracing. 4 | -------------------------------------------------------------------------------- /consumer-app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | group = 'com.github.burkaa01' 19 | version = '0.0.1-SNAPSHOT' 20 | sourceCompatibility = '1.8' 21 | 22 | repositories { 23 | mavenCentral() 24 | maven { 25 | url "http://packages.confluent.io/maven/" 26 | } 27 | } 28 | 29 | dependencies { 30 | // spring 31 | implementation 'org.springframework.boot:spring-boot-starter-web' 32 | 33 | // kafka 34 | 35 | // jaeger 36 | implementation 'io.jaegertracing:jaeger-client:0.33.1' 37 | implementation 'io.opentracing.contrib:opentracing-spring-cloud-starter:0.2.2' 38 | implementation 'io.opentracing.contrib:opentracing-kafka-client:0.0.16' 39 | implementation 'io.opentracing.contrib:opentracing-kafka-streams:0.0.16' 40 | implementation 'io.opentracing.contrib:opentracing-kafka-spring:0.0.16' 41 | } 42 | -------------------------------------------------------------------------------- /consumer-app/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/consumer-app/gradle.properties -------------------------------------------------------------------------------- /consumer-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/consumer-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /consumer-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 29 10:41:26 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /consumer-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /consumer-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /consumer-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'consumer-app' 2 | -------------------------------------------------------------------------------- /consumer-app/src/main/java/com/github/burkaa01/consumer/ConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ConsumerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ConsumerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /consumer-app/src/main/java/com/github/burkaa01/consumer/answer/AnswerProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer.answer; 2 | 3 | import com.google.gson.JsonObject; 4 | import io.opentracing.contrib.kafka.TracingKafkaConsumer; 5 | import io.opentracing.contrib.kafka.TracingKafkaProducer; 6 | import org.apache.kafka.clients.consumer.ConsumerRecord; 7 | import org.apache.kafka.clients.consumer.ConsumerRecords; 8 | import org.apache.kafka.clients.producer.ProducerRecord; 9 | import org.apache.kafka.clients.producer.RecordMetadata; 10 | import org.apache.kafka.common.header.Headers; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Value; 14 | import org.springframework.context.event.ContextRefreshedEvent; 15 | import org.springframework.context.event.EventListener; 16 | import org.springframework.stereotype.Component; 17 | 18 | @Component 19 | public class AnswerProducer { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(AnswerProducer.class); 22 | 23 | @Value("${topics.source-topic}") 24 | String sentenceTopic; 25 | @Value("${topics.target-topic}") 26 | String answerTopic; 27 | 28 | private final TracingKafkaConsumer sentenceKafkaConsumer; 29 | private final TracingKafkaProducer answerKafkaProducer; 30 | 31 | public AnswerProducer(TracingKafkaConsumer sentenceKafkaConsumer, TracingKafkaProducer answerKafkaProducer) { 32 | this.sentenceKafkaConsumer = sentenceKafkaConsumer; 33 | this.answerKafkaProducer = answerKafkaProducer; 34 | } 35 | 36 | @EventListener(ContextRefreshedEvent.class) 37 | public void contextRefreshedEvent() { 38 | listen(); 39 | } 40 | 41 | private void listen() { 42 | boolean forever = true; 43 | while (forever) { 44 | 45 | ConsumerRecords records = sentenceKafkaConsumer.poll(100L); 46 | int recordCount = records.count(); 47 | 48 | for (ConsumerRecord record : records) { 49 | String sentence = record.value(); 50 | LOGGER.info("{}: value={}", sentenceTopic, sentence); 51 | produceAnswer(sentence, record.headers()); 52 | } 53 | 54 | if (recordCount > 0) { 55 | sentenceKafkaConsumer.commitSync(); 56 | try { 57 | Thread.sleep(1000); 58 | } catch (InterruptedException exception) { 59 | LOGGER.error("Interrupted exception", exception); 60 | } 61 | } 62 | } 63 | answerKafkaProducer.close(); 64 | } 65 | 66 | private void produceAnswer(String sentence, Headers headers) { 67 | int firstNumber; 68 | int secondNumber; 69 | String[] numbers = sentence.split(" \\+ ", 2); 70 | try { 71 | firstNumber = Integer.parseInt(numbers[0]); 72 | secondNumber = Integer.parseInt(numbers[1]); 73 | } catch (NumberFormatException exception) { 74 | LOGGER.error("Exception parsing sentence", exception); 75 | return; 76 | } 77 | int answer = firstNumber + secondNumber; 78 | String completeSentence = firstNumber + " + " + secondNumber + " = " + answer; 79 | 80 | JsonObject json = new JsonObject(); 81 | json.addProperty("number", firstNumber); 82 | json.addProperty("random", secondNumber); 83 | json.addProperty("sentence", sentence); 84 | json.addProperty("completeSentence", completeSentence); 85 | json.addProperty("answer", answer); 86 | String jsonString = json.toString(); 87 | 88 | ProducerRecord record = new ProducerRecord(answerTopic, null, null, jsonString, headers); 89 | LOGGER.info("{}: value={}", answerTopic, jsonString); 90 | 91 | answerKafkaProducer.send(record, (RecordMetadata recordMetadata, Exception exception) -> { 92 | if (exception != null) { 93 | LOGGER.error("Exception producing answer", exception); 94 | } 95 | }); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /consumer-app/src/main/java/com/github/burkaa01/consumer/config/AnswerProducerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer.config; 2 | 3 | import io.opentracing.Tracer; 4 | import io.opentracing.contrib.kafka.TracingKafkaProducer; 5 | import org.apache.kafka.clients.producer.KafkaProducer; 6 | import org.apache.kafka.clients.producer.ProducerConfig; 7 | import org.apache.kafka.common.serialization.StringSerializer; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | import java.util.Properties; 13 | 14 | @Configuration 15 | public class AnswerProducerConfig { 16 | 17 | @Value("${kafka.bootstrap-servers}") 18 | String bootstrapServers; 19 | 20 | private final Tracer tracer; 21 | 22 | public AnswerProducerConfig(Tracer tracer) { 23 | this.tracer = tracer; 24 | } 25 | 26 | @Bean 27 | public TracingKafkaProducer answerKafkaProducer() { 28 | Properties properties = new Properties(); 29 | properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 30 | properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); 31 | properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); 32 | 33 | KafkaProducer producer = new KafkaProducer<>(properties); 34 | return new TracingKafkaProducer<>(producer, tracer); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /consumer-app/src/main/java/com/github/burkaa01/consumer/config/SentenceConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer.config; 2 | 3 | import io.opentracing.Tracer; 4 | import io.opentracing.contrib.kafka.TracingKafkaConsumer; 5 | import org.apache.kafka.clients.consumer.ConsumerConfig; 6 | import org.apache.kafka.clients.consumer.KafkaConsumer; 7 | import org.apache.kafka.common.serialization.StringDeserializer; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | import java.util.Collections; 13 | import java.util.Properties; 14 | 15 | @Configuration 16 | public class SentenceConsumerConfig { 17 | 18 | @Value("${kafka.bootstrap-servers}") 19 | String bootstrapServers; 20 | @Value("${kafka.consumer.enable-auto-commit}") 21 | String enableAutoCommit; 22 | @Value("${kafka.consumer.auto-offset-reset}") 23 | String autoOffsetReset; 24 | @Value("${kafka.consumer.max-poll-records}") 25 | String maxPollRecords; 26 | @Value("${kafka.consumer.group-id}") 27 | String groupId; 28 | @Value("${kafka.consumer.client-id}") 29 | String clientId; 30 | 31 | @Value("${topics.source-topic}") 32 | String sentenceTopic; 33 | 34 | private final Tracer tracer; 35 | 36 | public SentenceConsumerConfig(Tracer tracer) { 37 | this.tracer = tracer; 38 | } 39 | 40 | @Bean 41 | public TracingKafkaConsumer sentenceKafkaConsumer() { 42 | Properties properties = new Properties(); 43 | properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 44 | properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); 45 | properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); 46 | properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, groupId); 47 | properties.setProperty(ConsumerConfig.CLIENT_ID_CONFIG, clientId); 48 | properties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset); 49 | properties.setProperty(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit); 50 | properties.setProperty(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords); 51 | 52 | KafkaConsumer consumer = new KafkaConsumer<>(properties); 53 | consumer.subscribe(Collections.singletonList(sentenceTopic)); 54 | return new TracingKafkaConsumer<>(consumer, tracer); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /consumer-app/src/main/java/com/github/burkaa01/consumer/config/TracingConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer.config; 2 | 3 | import io.jaegertracing.internal.samplers.ConstSampler; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.util.GlobalTracer; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | @Configuration 13 | public class TracingConfig { 14 | 15 | @Value("${jaeger.tracer.host}") 16 | private String jaegerHost; 17 | @Value("${jaeger.tracer.port}") 18 | private Integer jaegerPort; 19 | @Value("${spring.application.name}") 20 | private String applicationName; 21 | 22 | @Bean 23 | public Tracer tracer() { 24 | return io.jaegertracing.Configuration.fromEnv(applicationName) 25 | .withSampler( 26 | io.jaegertracing.Configuration.SamplerConfiguration.fromEnv() 27 | .withType(ConstSampler.TYPE) 28 | .withParam(1)) 29 | .withReporter( 30 | io.jaegertracing.Configuration.ReporterConfiguration.fromEnv() 31 | .withLogSpans(true) 32 | .withFlushInterval(1000) 33 | .withMaxQueueSize(10000) 34 | .withSender( 35 | io.jaegertracing.Configuration.SenderConfiguration.fromEnv() 36 | .withAgentHost(jaegerHost) 37 | .withAgentPort(jaegerPort) 38 | )) 39 | .getTracer(); 40 | } 41 | 42 | @PostConstruct 43 | public void registerToGlobalTracer() { 44 | if (!GlobalTracer.isRegistered()) { 45 | GlobalTracer.register(tracer()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /consumer-app/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring.application.name: consumer-app 2 | 3 | kafka: 4 | bootstrap-servers: localhost:9092 5 | consumer: 6 | enable-auto-commit: false 7 | auto-offset-reset: earliest 8 | max-poll-records: 5 9 | group-id: consumer-app 10 | client-id: consumer-app 11 | 12 | jaeger.tracer: 13 | host: localhost 14 | port: 6831 15 | 16 | topics: 17 | source-topic: sentence-topic 18 | target-topic: answer-topic 19 | -------------------------------------------------------------------------------- /consumer-app/src/test/java/com/github/burkaa01/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.consumer; 2 | 3 | public class ConsumerApplicationTests { 4 | } 5 | -------------------------------------------------------------------------------- /consumer-app/src/test/resources/test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/consumer-app/src/test/resources/test.yml -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3.7' 3 | 4 | services: 5 | 6 | jaeger: 7 | image: jaegertracing/all-in-one 8 | container_name: jaeger 9 | ports: 10 | - "6831:6831/udp" 11 | - "16686:16686" 12 | 13 | rest-app: 14 | image: burkaa01/jaeger-tracing-kafka:rest-app 15 | container_name: rest-app 16 | depends_on: 17 | - jaeger 18 | environment: 19 | - jaeger.tracer.host=jaeger 20 | - jaeger.tracer.port=6831 21 | ports: 22 | - "8096:8096" 23 | restart: always 24 | 25 | zookeeper: 26 | image: confluentinc/cp-zookeeper 27 | hostname: zookeeper 28 | container_name: zookeeper 29 | ports: 30 | - "2181:2181" 31 | environment: 32 | ZOOKEEPER_CLIENT_PORT: 2181 33 | ZOOKEEPER_TICK_TIME: 2000 34 | 35 | broker: 36 | image: confluentinc/cp-enterprise-kafka 37 | hostname: broker 38 | container_name: broker 39 | depends_on: 40 | - zookeeper 41 | ports: 42 | - "9092:9092" 43 | - "29092:29092" 44 | environment: 45 | KAFKA_BROKER_ID: 1 46 | KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' 47 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,LOCAL://localhost:9092 48 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,LOCAL:PLAINTEXT 49 | KAFKA_METRIC_REPORTERS: io.confluent.metrics.reporter.ConfluentMetricsReporter 50 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 51 | KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 52 | CONFLUENT_METRICS_REPORTER_BOOTSTRAP_SERVERS: broker:29092 53 | CONFLUENT_METRICS_REPORTER_ZOOKEEPER_CONNECT: zookeeper:2181 54 | CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS: 1 55 | CONFLUENT_METRICS_ENABLE: 'true' 56 | CONFLUENT_SUPPORT_CUSTOMER_ID: 'anonymous' 57 | 58 | topic-configuration: 59 | image: burkaa01/jaeger-tracing-kafka:topic-configuration 60 | container_name: topic-configuration 61 | depends_on: 62 | - zookeeper 63 | - broker 64 | environment: 65 | - spring.kafka.bootstrap-servers=broker:29092 66 | 67 | connect: 68 | image: confluentinc/cp-kafka-connect 69 | hostname: connect 70 | container_name: connect 71 | depends_on: 72 | - zookeeper 73 | - broker 74 | - topic-configuration 75 | volumes: 76 | - ./kafka-connect:/usr/share/data 77 | ports: 78 | - "8083:8083" 79 | environment: 80 | CONNECT_BOOTSTRAP_SERVERS: 'broker:29092' 81 | CONNECT_REST_ADVERTISED_HOST_NAME: connect 82 | CONNECT_REST_PORT: 8083 83 | CONNECT_GROUP_ID: compose-connect-group 84 | CONNECT_CONFIG_STORAGE_TOPIC: docker-connect-configs 85 | CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: 1 86 | CONNECT_OFFSET_FLUSH_INTERVAL_MS: 10000 87 | CONNECT_OFFSET_STORAGE_TOPIC: docker-connect-offsets 88 | CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: 1 89 | CONNECT_STATUS_STORAGE_TOPIC: docker-connect-status 90 | CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: 1 91 | CONNECT_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter 92 | CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter 93 | CONNECT_INTERNAL_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter 94 | CONNECT_INTERNAL_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter 95 | CONNECT_ZOOKEEPER_CONNECT: 'zookeeper:2181' 96 | CONNECT_PLUGIN_PATH: /usr/share/java 97 | CONNECT_LOG4J_LOGGERS: org.apache.zookeeper=ERROR,org.I0Itec.zkclient=ERROR,org.reflections=ERROR 98 | 99 | rest-proxy: 100 | image: confluentinc/cp-kafka-rest:latest 101 | depends_on: 102 | - zookeeper 103 | - broker 104 | ports: 105 | - 8082:8082 106 | hostname: rest-proxy 107 | container_name: rest-proxy 108 | environment: 109 | KAFKA_REST_HOST_NAME: rest-proxy 110 | KAFKA_REST_BOOTSTRAP_SERVERS: 'broker:29092' 111 | KAFKA_REST_LISTENERS: "http://0.0.0.0:8082" 112 | 113 | control-center: 114 | image: confluentinc/cp-enterprise-control-center 115 | hostname: control-center 116 | container_name: control-center 117 | depends_on: 118 | - zookeeper 119 | - broker 120 | - connect 121 | ports: 122 | - "9021:9021" 123 | environment: 124 | CONTROL_CENTER_BOOTSTRAP_SERVERS: 'broker:29092' 125 | CONTROL_CENTER_ZOOKEEPER_CONNECT: 'zookeeper:2181' 126 | CONTROL_CENTER_CONNECT_CLUSTER: 'connect:8083' 127 | CONTROL_CENTER_REPLICATION_FACTOR: 1 128 | CONTROL_CENTER_INTERNAL_TOPICS_PARTITIONS: 1 129 | CONTROL_CENTER_MONITORING_INTERCEPTOR_TOPIC_PARTITIONS: 1 130 | CONFLUENT_METRICS_TOPIC_REPLICATION: 1 131 | PORT: 9021 132 | 133 | ksql-server: 134 | image: confluentinc/cp-ksql-server:5.0.0-beta30 135 | hostname: ksql-server 136 | container_name: ksql-server 137 | depends_on: 138 | - broker 139 | - connect 140 | ports: 141 | - "8088:8088" 142 | environment: 143 | KSQL_CONFIG_DIR: "/etc/ksql" 144 | KSQL_LOG4J_OPTS: "-Dlog4j.configuration=file:/etc/ksql/log4j-rolling.properties" 145 | KSQL_BOOTSTRAP_SERVERS: "broker:29092" 146 | KSQL_HOST_NAME: ksql-server 147 | KSQL_APPLICATION_ID: "cp-all-in-one" 148 | KSQL_LISTENERS: "http://0.0.0.0:8088" 149 | KSQL_CACHE_MAX_BYTES_BUFFERING: 0 150 | KSQL_PRODUCER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor" 151 | KSQL_CONSUMER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor" 152 | 153 | ksql-cli: 154 | image: confluentinc/cp-ksql-cli:5.0.0-beta30 155 | container_name: ksql-cli 156 | depends_on: 157 | - broker 158 | - connect 159 | - ksql-server 160 | 161 | elasticsearch: 162 | image: docker.elastic.co/elasticsearch/elasticsearch:6.5.0 163 | container_name: elasticsearch 164 | environment: 165 | - discovery.type=single-node 166 | volumes: 167 | - ElasticData:/usr/share/elasticsearch/data 168 | ports: 169 | - 9200:9200 170 | - 9300:9300 171 | 172 | stream-app: 173 | image: burkaa01/jaeger-tracing-kafka:stream-app 174 | container_name: stream-app 175 | depends_on: 176 | - jaeger 177 | - zookeeper 178 | - broker 179 | - topic-configuration 180 | - connect 181 | environment: 182 | - spring.kafka.bootstrap-servers=broker:29092 183 | - jaeger.tracer.host=jaeger 184 | - jaeger.tracer.port=6831 185 | restart: always 186 | 187 | spring-consumer-app: 188 | image: burkaa01/jaeger-tracing-kafka:spring-consumer-app 189 | container_name: spring-consumer-app 190 | depends_on: 191 | - jaeger 192 | - rest-app 193 | - zookeeper 194 | - broker 195 | - topic-configuration 196 | - connect 197 | environment: 198 | - spring.kafka.bootstrap-servers=broker:29092 199 | - rest-app.url=http://rest-app:8096 200 | - jaeger.tracer.host=jaeger 201 | - jaeger.tracer.port=6831 202 | restart: always 203 | 204 | consumer-app: 205 | image: burkaa01/jaeger-tracing-kafka:consumer-app 206 | container_name: consumer-app 207 | depends_on: 208 | - jaeger 209 | - zookeeper 210 | - broker 211 | - topic-configuration 212 | - connect 213 | environment: 214 | - kafka.bootstrap-servers=broker:29092 215 | - jaeger.tracer.host=jaeger 216 | - jaeger.tracer.port=6831 217 | restart: always 218 | 219 | volumes: 220 | ElasticData: 221 | ConnectData: 222 | -------------------------------------------------------------------------------- /jaeger-tracing-kafka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/jaeger-tracing-kafka.png -------------------------------------------------------------------------------- /kafka-connect/README.md: -------------------------------------------------------------------------------- 1 | # kafka-connect 2 | 3 | This is an example of configuration for Kafka Connect. The configuration for the file source connector is already setup in `./file-source/file-source.json`. The following curl command will configure the connector pointed at the `numbers.txt` file (which is mounted to the docker container at `/usr/share/data/file-source`): 4 | 5 | ```bash 6 | cd ./file-source 7 | curl -X POST -H "Content-Type: application/json" --data @file-source.json http://localhost:8083/connectors 8 | curl http://localhost:8083/connectors 9 | ``` 10 | 11 | The configuration for the Elasticsearch sink connector is configured in `./elastic-sink/elastic-sink.json`. The following curl command will configure the connector: 12 | 13 | ```bash 14 | cd ./elastic-sink 15 | curl -X POST -H "Content-Type: application/json" --data @elastic-sink.json http://localhost:8083/connectors 16 | curl http://localhost:8083/connectors 17 | ``` 18 | -------------------------------------------------------------------------------- /kafka-connect/elastic-sink/elastic-sink.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "answer-elastic-sink", 3 | "config": { 4 | "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector", 5 | "topics": "answer-topic", 6 | "key.converter": "org.apache.kafka.connect.json.JsonConverter", 7 | "key.converter.schemas.enable": "false", 8 | "value.converter": "org.apache.kafka.connect.json.JsonConverter", 9 | "value.converter.schemas.enable": "false", 10 | "key.ignore": "true", 11 | "schema.ignore": "true", 12 | "tasks.max": "1", 13 | "connection.url": "http://elasticsearch:9200", 14 | "type.name": "kafka-connect" 15 | } 16 | } -------------------------------------------------------------------------------- /kafka-connect/file-source/file-source.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "numbers-file-source", 3 | "config": { 4 | "connector.class": "FileStreamSource", 5 | "value.converter": "org.apache.kafka.connect.storage.StringConverter", 6 | "tasks.max": "1", 7 | "file": "/usr/share/data/file-source/numbers.txt", 8 | "topic": "number-topic" 9 | } 10 | } -------------------------------------------------------------------------------- /kafka-connect/file-source/numbers.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10 11 | 11 12 | 12 13 | 13 14 | 14 15 | 15 16 | 16 17 | 17 18 | 18 19 | 19 20 | 20 21 | 21 22 | 22 23 | 23 24 | 24 25 | 25 26 | 26 27 | 27 28 | 28 29 | 29 30 | 30 31 | 31 32 | 32 33 | 33 34 | 34 35 | 35 36 | 36 37 | 37 38 | 38 39 | 39 40 | 40 41 | 41 42 | 42 43 | 43 44 | 44 45 | 45 46 | 46 47 | 47 48 | 48 49 | 49 50 | 50 51 | -------------------------------------------------------------------------------- /rest-app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | -------------------------------------------------------------------------------- /rest-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | COPY build/libs/rest-app-0.0.1-SNAPSHOT.jar /app.jar 4 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /rest-app/README.md: -------------------------------------------------------------------------------- 1 | # rest-app 2 | 3 | This is an example of a REST application with Jaeger tracing. 4 | -------------------------------------------------------------------------------- /rest-app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | group = 'com.github.burkaa01' 19 | version = '0.0.1-SNAPSHOT' 20 | sourceCompatibility = '1.8' 21 | 22 | repositories { 23 | mavenCentral() 24 | } 25 | 26 | dependencies { 27 | // spring 28 | implementation 'org.springframework.boot:spring-boot-starter-web' 29 | 30 | // jaeger 31 | implementation 'io.jaegertracing:jaeger-client:0.33.1' 32 | implementation 'io.opentracing.contrib:opentracing-spring-cloud-starter:0.2.2' 33 | } 34 | -------------------------------------------------------------------------------- /rest-app/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/rest-app/gradle.properties -------------------------------------------------------------------------------- /rest-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/rest-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /rest-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 29 10:36:25 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /rest-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /rest-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /rest-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rest-app' 2 | -------------------------------------------------------------------------------- /rest-app/src/main/java/com/github/burkaa01/rest/RestApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.rest; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rest-app/src/main/java/com/github/burkaa01/rest/config/TracingConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.rest.config; 2 | 3 | import io.jaegertracing.internal.samplers.ConstSampler; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.util.GlobalTracer; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | @Configuration 13 | public class TracingConfig { 14 | 15 | @Value("${jaeger.tracer.host}") 16 | private String jaegerHost; 17 | @Value("${jaeger.tracer.port}") 18 | private Integer jaegerPort; 19 | @Value("${spring.application.name}") 20 | private String applicationName; 21 | 22 | @Bean 23 | public Tracer tracer() { 24 | return io.jaegertracing.Configuration.fromEnv(applicationName) 25 | .withSampler( 26 | io.jaegertracing.Configuration.SamplerConfiguration.fromEnv() 27 | .withType(ConstSampler.TYPE) 28 | .withParam(1)) 29 | .withReporter( 30 | io.jaegertracing.Configuration.ReporterConfiguration.fromEnv() 31 | .withLogSpans(true) 32 | .withFlushInterval(1000) 33 | .withMaxQueueSize(10000) 34 | .withSender( 35 | io.jaegertracing.Configuration.SenderConfiguration.fromEnv() 36 | .withAgentHost(jaegerHost) 37 | .withAgentPort(jaegerPort) 38 | )) 39 | .getTracer(); 40 | } 41 | 42 | @PostConstruct 43 | public void registerToGlobalTracer() { 44 | if (!GlobalTracer.isRegistered()) { 45 | GlobalTracer.register(tracer()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rest-app/src/main/java/com/github/burkaa01/rest/controller/RandomRestController.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.rest.controller; 2 | 3 | import io.opentracing.Span; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.contrib.spring.web.client.HttpHeadersCarrier; 6 | import io.opentracing.propagation.Format; 7 | import io.opentracing.util.GlobalTracer; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.http.HttpHeaders; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.Random; 17 | 18 | @RestController 19 | public class RandomRestController { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(RandomRestController.class); 22 | private static final String RANDOM_NUMBER_TAG = "random.number"; 23 | 24 | @PostMapping(path = "/random", produces = {"application/json"}) 25 | public ResponseEntity example() { 26 | 27 | int randomNumber = new Random().nextInt(10); 28 | LOGGER.info("{} was {}", RANDOM_NUMBER_TAG, randomNumber); 29 | 30 | Tracer tracer = GlobalTracer.get(); 31 | Span span = tracer.activeSpan(); 32 | span.setTag(RANDOM_NUMBER_TAG, randomNumber); 33 | 34 | HttpHeaders responseHeaders = new HttpHeaders(); 35 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersCarrier(responseHeaders)); 36 | return new ResponseEntity<>(Integer.toString(randomNumber), responseHeaders, HttpStatus.OK); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rest-app/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring.application.name: rest-app 2 | 3 | jaeger.tracer: 4 | host: localhost 5 | port: 6831 6 | 7 | server.port: 8096 8 | -------------------------------------------------------------------------------- /rest-app/src/test/java/com/github/burkaa01/rest/RestApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.rest; 2 | 3 | public class RestApplicationTests { 4 | } 5 | -------------------------------------------------------------------------------- /rest-app/src/test/resources/test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/rest-app/src/test/resources/test.yml -------------------------------------------------------------------------------- /spring-consumer-app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /spring-consumer-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | COPY build/libs/spring-consumer-app-0.0.1-SNAPSHOT.jar /app.jar 4 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /spring-consumer-app/README.md: -------------------------------------------------------------------------------- 1 | # spring-consumer-app 2 | 3 | This is an example of a Spring Kafka consumer and producer application with Jaeger tracing. 4 | -------------------------------------------------------------------------------- /spring-consumer-app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | group = 'com.github.burkaa01' 19 | version = '0.0.1-SNAPSHOT' 20 | sourceCompatibility = '1.8' 21 | 22 | repositories { 23 | mavenCentral() 24 | maven { 25 | url "http://packages.confluent.io/maven/" 26 | } 27 | } 28 | 29 | dependencies { 30 | // spring 31 | implementation 'org.springframework.boot:spring-boot-starter-web' 32 | implementation 'org.springframework.kafka:spring-kafka' 33 | 34 | // jaeger 35 | implementation 'io.jaegertracing:jaeger-client:0.33.1' 36 | implementation 'io.opentracing.contrib:opentracing-spring-cloud-starter:0.2.2' 37 | implementation 'io.opentracing.contrib:opentracing-kafka-client:0.0.16' 38 | implementation 'io.opentracing.contrib:opentracing-kafka-streams:0.0.16' 39 | implementation 'io.opentracing.contrib:opentracing-kafka-spring:0.0.16' 40 | } 41 | -------------------------------------------------------------------------------- /spring-consumer-app/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/spring-consumer-app/gradle.properties -------------------------------------------------------------------------------- /spring-consumer-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/spring-consumer-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-consumer-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 29 10:41:26 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /spring-consumer-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /spring-consumer-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /spring-consumer-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-consumer-app' 2 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/SpringConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.kafka.annotation.EnableKafka; 6 | 7 | @EnableKafka 8 | @SpringBootApplication 9 | public class SpringConsumerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringConsumerApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/config/NumberConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer.config; 2 | 3 | import io.opentracing.contrib.kafka.TracingConsumerInterceptor; 4 | import org.apache.kafka.clients.consumer.ConsumerConfig; 5 | import org.apache.kafka.common.serialization.IntegerDeserializer; 6 | import org.apache.kafka.common.serialization.StringDeserializer; 7 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 11 | import org.springframework.kafka.core.ConsumerFactory; 12 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 13 | 14 | import java.util.Collections; 15 | import java.util.Map; 16 | 17 | import static org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode.MANUAL; 18 | 19 | @Configuration 20 | public class NumberConsumerConfig { 21 | 22 | private final KafkaProperties kafkaProperties; 23 | 24 | public NumberConsumerConfig(KafkaProperties kafkaProperties) { 25 | this.kafkaProperties = kafkaProperties; 26 | } 27 | 28 | @Bean 29 | public ConcurrentKafkaListenerContainerFactory numberContainerFactory() { 30 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); 31 | factory.getContainerProperties().setAckMode(MANUAL); 32 | factory.setConsumerFactory(numberConsumerFactory()); 33 | return factory; 34 | } 35 | 36 | @Bean 37 | public ConsumerFactory kafkaConsumerFactory() { 38 | Map properties = kafkaProperties.buildConsumerProperties(); 39 | return new DefaultKafkaConsumerFactory(properties); 40 | } 41 | 42 | @Bean 43 | public ConsumerFactory numberConsumerFactory() { 44 | Map properties = kafkaProperties.buildConsumerProperties(); 45 | properties.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, Collections.singletonList(TracingConsumerInterceptor.class)); 46 | properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 47 | properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class); 48 | return new DefaultKafkaConsumerFactory<>(properties); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/config/SentenceProducerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer.config; 2 | 3 | import io.opentracing.contrib.kafka.TracingProducerInterceptor; 4 | import org.apache.kafka.clients.producer.ProducerConfig; 5 | import org.apache.kafka.common.serialization.StringSerializer; 6 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.kafka.core.DefaultKafkaProducerFactory; 10 | import org.springframework.kafka.core.KafkaTemplate; 11 | import org.springframework.kafka.core.ProducerFactory; 12 | 13 | import java.util.Collections; 14 | import java.util.Map; 15 | 16 | @Configuration 17 | public class SentenceProducerConfig { 18 | 19 | private final KafkaProperties kafkaProperties; 20 | 21 | public SentenceProducerConfig(KafkaProperties kafkaProperties) { 22 | this.kafkaProperties = kafkaProperties; 23 | } 24 | 25 | @Bean 26 | public KafkaTemplate sentenceTemplate() { 27 | return new KafkaTemplate<>(sentenceProducerFactory()); 28 | } 29 | 30 | @Bean 31 | public ProducerFactory sentenceProducerFactory() { 32 | Map properties = kafkaProperties.buildProducerProperties(); 33 | properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, Collections.singletonList(TracingProducerInterceptor.class)); 34 | properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 35 | properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 36 | return new DefaultKafkaProducerFactory<>(properties); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/config/TracingChildRestTemplateInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer.config; 2 | 3 | import io.opentracing.Scope; 4 | import io.opentracing.SpanContext; 5 | import io.opentracing.Tracer; 6 | import io.opentracing.contrib.kafka.TracingKafkaUtils; 7 | import io.opentracing.contrib.spring.web.client.HttpHeadersCarrier; 8 | import io.opentracing.contrib.spring.web.client.RestTemplateSpanDecorator; 9 | import io.opentracing.contrib.spring.web.client.TracingRestTemplateInterceptor; 10 | import io.opentracing.propagation.Format; 11 | import io.opentracing.tag.Tags; 12 | import io.opentracing.util.GlobalTracer; 13 | import org.apache.kafka.common.header.Headers; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.http.HttpRequest; 17 | import org.springframework.http.client.ClientHttpRequestExecution; 18 | import org.springframework.http.client.ClientHttpRequestInterceptor; 19 | import org.springframework.http.client.ClientHttpResponse; 20 | 21 | import java.io.IOException; 22 | 23 | /** 24 | * A version of OpenTracing's Spring RestTemplate integration {@link TracingRestTemplateInterceptor} to be used when 25 | * a request is a child of another span in the trace. In our case, the request in question is a child of a span from 26 | * our Kafka consumer. 27 | */ 28 | public class TracingChildRestTemplateInterceptor implements ClientHttpRequestInterceptor { 29 | 30 | private static final Logger LOGGER = LoggerFactory.getLogger(TracingChildRestTemplateInterceptor.class); 31 | private static final RestTemplateSpanDecorator REST_SPAN_DECORATOR = new RestTemplateSpanDecorator.StandardTags(); 32 | 33 | private Tracer tracer; 34 | private Headers headers; 35 | 36 | public TracingChildRestTemplateInterceptor(Headers headers) { 37 | this.tracer = GlobalTracer.get(); 38 | this.headers = headers; 39 | } 40 | 41 | @Override 42 | public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, ClientHttpRequestExecution execution) throws IOException { 43 | ClientHttpResponse httpResponse; 44 | 45 | SpanContext parentContext = null; 46 | if (headers != null && headers.toArray().length > 0) { 47 | parentContext = TracingKafkaUtils.extractSpanContext(headers, tracer); 48 | } 49 | 50 | try (Scope scope = tracer.buildSpan(httpRequest.getMethod().toString()) 51 | .asChildOf(parentContext) 52 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) 53 | .startActive(true)) { 54 | 55 | tracer.inject(scope.span().context(), Format.Builtin.HTTP_HEADERS, 56 | new HttpHeadersCarrier(httpRequest.getHeaders())); 57 | 58 | try { 59 | REST_SPAN_DECORATOR.onRequest(httpRequest, scope.span()); 60 | } catch (RuntimeException exception) { 61 | LOGGER.error("Exception decorating span", exception); 62 | } 63 | 64 | try { 65 | httpResponse = execution.execute(httpRequest, body); 66 | } catch (Exception exception) { 67 | try { 68 | REST_SPAN_DECORATOR.onError(httpRequest, exception, scope.span()); 69 | } catch (RuntimeException ex) { 70 | LOGGER.error("Exception decorating span", ex); 71 | } 72 | throw exception; 73 | } 74 | 75 | try { 76 | REST_SPAN_DECORATOR.onResponse(httpRequest, httpResponse, scope.span()); 77 | } catch (RuntimeException exception) { 78 | LOGGER.error("Exception decorating span", exception); 79 | } 80 | } 81 | return httpResponse; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/config/TracingConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer.config; 2 | 3 | import io.jaegertracing.internal.samplers.ConstSampler; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.util.GlobalTracer; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | @Configuration 13 | public class TracingConfig { 14 | 15 | @Value("${jaeger.tracer.host}") 16 | private String jaegerHost; 17 | @Value("${jaeger.tracer.port}") 18 | private Integer jaegerPort; 19 | @Value("${spring.application.name}") 20 | private String applicationName; 21 | 22 | @Bean 23 | public Tracer tracer() { 24 | return io.jaegertracing.Configuration.fromEnv(applicationName) 25 | .withSampler( 26 | io.jaegertracing.Configuration.SamplerConfiguration.fromEnv() 27 | .withType(ConstSampler.TYPE) 28 | .withParam(1)) 29 | .withReporter( 30 | io.jaegertracing.Configuration.ReporterConfiguration.fromEnv() 31 | .withLogSpans(true) 32 | .withFlushInterval(1000) 33 | .withMaxQueueSize(10000) 34 | .withSender( 35 | io.jaegertracing.Configuration.SenderConfiguration.fromEnv() 36 | .withAgentHost(jaegerHost) 37 | .withAgentPort(jaegerPort) 38 | )) 39 | .getTracer(); 40 | } 41 | 42 | @PostConstruct 43 | public void registerToGlobalTracer() { 44 | if (!GlobalTracer.isRegistered()) { 45 | GlobalTracer.register(tracer()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/java/com/github/burkaa01/springconsumer/sentence/SentenceProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer.sentence; 2 | 3 | import com.github.burkaa01.springconsumer.config.TracingChildRestTemplateInterceptor; 4 | import org.apache.kafka.clients.consumer.ConsumerRecord; 5 | import org.apache.kafka.clients.producer.ProducerRecord; 6 | import org.apache.kafka.common.header.Header; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.http.HttpEntity; 11 | import org.springframework.http.HttpHeaders; 12 | import org.springframework.http.HttpMethod; 13 | import org.springframework.kafka.annotation.KafkaListener; 14 | import org.springframework.kafka.core.KafkaTemplate; 15 | import org.springframework.kafka.support.Acknowledgment; 16 | import org.springframework.stereotype.Component; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import java.io.UnsupportedEncodingException; 20 | import java.net.URLDecoder; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | @Component 26 | public class SentenceProducer { 27 | 28 | private static final Logger LOGGER = LoggerFactory.getLogger(SentenceProducer.class); 29 | private static final String TRACING_SPAN_CONTEXT_KEY = "uber-trace-id"; 30 | private static final String TRACING_SECOND_SPAN_CONTEXT_KEY = "second_span_uber-trace-id"; 31 | 32 | @Value("${topics.source-topic}") 33 | String numberTopic; 34 | @Value("${topics.target-topic}") 35 | String sentenceTopic; 36 | @Value("${rest-app.url}") 37 | String restAppUrl; 38 | @Value("${rest-app.api}") 39 | String restAppApi; 40 | 41 | private final KafkaTemplate sentenceTemplate; 42 | 43 | public SentenceProducer(KafkaTemplate sentenceTemplate) { 44 | this.sentenceTemplate = sentenceTemplate; 45 | } 46 | 47 | @KafkaListener(topics = "${topics.source-topic}", containerFactory = "numberContainerFactory") 48 | public void listen(ConsumerRecord record, Acknowledgment acks) { 49 | if (record.value() == null) { 50 | return; 51 | } 52 | int number = record.value(); 53 | LOGGER.info("{}: value={}", numberTopic, number); 54 | 55 | /* call rest app */ 56 | final String url = restAppUrl + restAppApi; 57 | HttpEntity response = sendToRestApp(url, record); 58 | String restAppResponse = response.getBody(); 59 | LOGGER.info("{}: value={}", url, restAppResponse); 60 | 61 | updateTracingHeaders(record, response.getHeaders()); 62 | 63 | int secondNumber; 64 | try { 65 | secondNumber = Integer.parseInt(restAppResponse); 66 | } catch (NumberFormatException e) { 67 | return; 68 | } 69 | 70 | /* produce resulting sentence and send to sentence topic */ 71 | produceSentence(number, secondNumber, record.headers()); 72 | 73 | /* acknowledge message */ 74 | acks.acknowledge(); 75 | } 76 | 77 | private HttpEntity sendToRestApp(String url, ConsumerRecord record) { 78 | RestTemplate restTemplate = new RestTemplate(); 79 | restTemplate.setInterceptors(Collections.singletonList(new TracingChildRestTemplateInterceptor(record.headers()))); 80 | return restTemplate.exchange(url, HttpMethod.POST, null, String.class); 81 | } 82 | 83 | private void produceSentence(int firstNumber, int secondNumber, Iterable
headers) { 84 | String sentence = firstNumber + " + " + secondNumber; 85 | LOGGER.info("{}: value={}", sentenceTopic, sentence); 86 | 87 | ProducerRecord producerRecord = new ProducerRecord( 88 | sentenceTopic, 89 | null, 90 | null, 91 | sentence, 92 | headers); 93 | sentenceTemplate.send(producerRecord); 94 | } 95 | 96 | private void updateTracingHeaders(ConsumerRecord record, HttpHeaders httpHeaders) { 97 | String spanContext = spanContextFromHttpHeaders(httpHeaders); 98 | if (spanContext != null) { 99 | record.headers().remove(TRACING_SPAN_CONTEXT_KEY); 100 | record.headers().remove(TRACING_SECOND_SPAN_CONTEXT_KEY); 101 | record.headers().add(TRACING_SPAN_CONTEXT_KEY, spanContext.getBytes(StandardCharsets.UTF_8)); 102 | } 103 | } 104 | 105 | private String spanContextFromHttpHeaders(HttpHeaders headers) { 106 | List spanContextHeader = headers.get(TRACING_SPAN_CONTEXT_KEY); 107 | if (spanContextHeader == null || spanContextHeader.isEmpty()) { 108 | return null; 109 | } 110 | try { 111 | return URLDecoder.decode(String.join("", spanContextHeader), StandardCharsets.UTF_8.toString()); 112 | } catch (UnsupportedEncodingException exception) { 113 | LOGGER.error("Exception reading span context from HttpHeader", exception); 114 | return null; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /spring-consumer-app/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: spring-consumer-app 3 | kafka: 4 | bootstrap-servers: localhost:9092 5 | consumer: 6 | enable-auto-commit: false 7 | auto-offset-reset: earliest 8 | group-id: spring-consumer-app 9 | client-id: spring-consumer-app 10 | 11 | jaeger.tracer: 12 | host: localhost 13 | port: 6831 14 | 15 | topics: 16 | source-topic: even-topic 17 | target-topic: sentence-topic 18 | 19 | rest-app: 20 | url: http://localhost:8096 21 | api: /random -------------------------------------------------------------------------------- /spring-consumer-app/src/test/java/com/github/burkaa01/springconsumer/SpringConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.springconsumer; 2 | 3 | public class SpringConsumerApplicationTests { 4 | } 5 | -------------------------------------------------------------------------------- /spring-consumer-app/src/test/resources/test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/spring-consumer-app/src/test/resources/test.yml -------------------------------------------------------------------------------- /stream-app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /stream-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | COPY build/libs/stream-app-0.0.1-SNAPSHOT.jar /app.jar 4 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /stream-app/README.md: -------------------------------------------------------------------------------- 1 | # stream-app 2 | 3 | This is an example of a Kafka Stream application with Jaeger tracing. 4 | -------------------------------------------------------------------------------- /stream-app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | group = 'com.github.burkaa01' 19 | version = '0.0.1-SNAPSHOT' 20 | sourceCompatibility = '1.8' 21 | 22 | repositories { 23 | mavenCentral() 24 | maven { 25 | url "http://packages.confluent.io/maven/" 26 | } 27 | } 28 | 29 | dependencies { 30 | // spring 31 | implementation 'org.springframework.boot:spring-boot-starter' 32 | implementation 'org.springframework.kafka:spring-kafka' 33 | 34 | // kafka 35 | implementation "org.apache.kafka:kafka-clients:2.1.0" 36 | implementation "org.apache.kafka:kafka-streams:2.1.0" 37 | 38 | // jaeger 39 | implementation 'io.jaegertracing:jaeger-client:0.33.1' 40 | implementation 'io.opentracing.contrib:opentracing-kafka-client:0.0.16' 41 | implementation 'io.opentracing.contrib:opentracing-kafka-streams:0.0.16' 42 | implementation 'io.opentracing.contrib:opentracing-kafka-spring:0.0.16' 43 | } 44 | -------------------------------------------------------------------------------- /stream-app/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/stream-app/gradle.properties -------------------------------------------------------------------------------- /stream-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/stream-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /stream-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 21 11:38:34 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /stream-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /stream-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /stream-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'stream-app' 2 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/StreamApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.kafka.annotation.EnableKafkaStreams; 6 | 7 | @EnableKafkaStreams 8 | @SpringBootApplication 9 | public class StreamApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(StreamApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/config/DeadLetterProducerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.config; 2 | 3 | import io.opentracing.contrib.kafka.TracingProducerInterceptor; 4 | import org.apache.kafka.clients.producer.ProducerConfig; 5 | import org.apache.kafka.common.serialization.IntegerSerializer; 6 | import org.apache.kafka.common.serialization.StringSerializer; 7 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.kafka.core.DefaultKafkaProducerFactory; 11 | import org.springframework.kafka.core.KafkaTemplate; 12 | import org.springframework.kafka.core.ProducerFactory; 13 | 14 | import java.util.Collections; 15 | import java.util.Map; 16 | 17 | @Configuration 18 | public class DeadLetterProducerConfig { 19 | 20 | private final KafkaProperties kafkaProperties; 21 | 22 | public DeadLetterProducerConfig(KafkaProperties kafkaProperties) { 23 | this.kafkaProperties = kafkaProperties; 24 | } 25 | 26 | @Bean 27 | public KafkaTemplate deadLetterTemplate() { 28 | return new KafkaTemplate<>(deadLetterProducerFactory()); 29 | } 30 | 31 | @Bean 32 | public ProducerFactory deadLetterProducerFactory() { 33 | Map properties = kafkaProperties.buildProducerProperties(); 34 | properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, Collections.singletonList(TracingProducerInterceptor.class)); 35 | properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 36 | properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class); 37 | return new DefaultKafkaProducerFactory<>(properties); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/config/DividerStreamsConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.config; 2 | 3 | import org.apache.kafka.streams.StreamsConfig; 4 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; 8 | 9 | import java.util.Map; 10 | 11 | @Configuration 12 | public class DividerStreamsConfig { 13 | 14 | @Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) 15 | public StreamsConfig streamsConfig(KafkaProperties kafkaProperties) { 16 | Map properties = kafkaProperties.buildConsumerProperties(); 17 | properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapServers()); 18 | properties.put(StreamsConfig.APPLICATION_ID_CONFIG, kafkaProperties.getConsumer().getGroupId()); 19 | return new StreamsConfig(properties); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/config/TracingConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.config; 2 | 3 | import io.jaegertracing.internal.samplers.ConstSampler; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.contrib.kafka.streams.TracingKafkaClientSupplier; 6 | import io.opentracing.util.GlobalTracer; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.kafka.core.StreamsBuilderFactoryBean; 11 | 12 | import javax.annotation.PostConstruct; 13 | 14 | @Configuration 15 | public class TracingConfig { 16 | 17 | @Value("${jaeger.tracer.host}") 18 | private String jaegerHost; 19 | @Value("${jaeger.tracer.port}") 20 | private Integer jaegerPort; 21 | @Value("${spring.application.name}") 22 | private String applicationName; 23 | 24 | private final StreamsBuilderFactoryBean streamsBuilderFactory; 25 | 26 | public TracingConfig(StreamsBuilderFactoryBean streamsBuilderFactory) { 27 | this.streamsBuilderFactory = streamsBuilderFactory; 28 | } 29 | 30 | @Bean 31 | public Tracer tracer() { 32 | return io.jaegertracing.Configuration.fromEnv(applicationName) 33 | .withSampler( 34 | io.jaegertracing.Configuration.SamplerConfiguration.fromEnv() 35 | .withType(ConstSampler.TYPE) 36 | .withParam(1)) 37 | .withReporter( 38 | io.jaegertracing.Configuration.ReporterConfiguration.fromEnv() 39 | .withLogSpans(true) 40 | .withFlushInterval(1000) 41 | .withMaxQueueSize(10000) 42 | .withSender( 43 | io.jaegertracing.Configuration.SenderConfiguration.fromEnv() 44 | .withAgentHost(jaegerHost) 45 | .withAgentPort(jaegerPort) 46 | )) 47 | .getTracer(); 48 | } 49 | 50 | @PostConstruct 51 | public void registerToGlobalTracer() { 52 | if (!GlobalTracer.isRegistered()) { 53 | GlobalTracer.register(tracer()); 54 | } 55 | } 56 | 57 | @PostConstruct 58 | public void setClientSupplierForStreams() { 59 | streamsBuilderFactory.setClientSupplier(new TracingKafkaClientSupplier(tracer())); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/divider/DividerMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.divider; 2 | 3 | import org.apache.kafka.clients.producer.ProducerRecord; 4 | import org.apache.kafka.common.header.Headers; 5 | import org.apache.kafka.streams.KeyValue; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.kafka.core.KafkaTemplate; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class DividerMapper { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(DividerMapper.class); 16 | 17 | @Value("${topics.dead-letter-topic}") 18 | private String deadLetterTopic; 19 | 20 | private final KafkaTemplate deadLetterTemplate; 21 | 22 | public DividerMapper(KafkaTemplate deadLetterTemplate) { 23 | this.deadLetterTemplate = deadLetterTemplate; 24 | } 25 | 26 | public KeyValue map(String key, ValueWithHeaders valueWithHeaders) { 27 | if (valueWithHeaders == null) { 28 | return new KeyValue<>(null, null); 29 | } 30 | 31 | int number; 32 | try { 33 | number = Integer.parseInt(valueWithHeaders.getValue()); 34 | } catch (NumberFormatException e) { 35 | return new KeyValue<>(null, null); 36 | } 37 | 38 | if (isOddNumber(number)) { 39 | toDeadLetterTopic(key, number, valueWithHeaders.getHeaders()); 40 | return new KeyValue<>(null, null); 41 | } 42 | return new KeyValue<>(key, number); 43 | } 44 | 45 | private void toDeadLetterTopic(String key, int value, Headers headers) { 46 | LOGGER.info("{}: value={}", deadLetterTopic, value); 47 | 48 | ProducerRecord deadLetterRecord = new ProducerRecord<>( 49 | deadLetterTopic, 50 | null, 51 | key, 52 | value, 53 | headers); 54 | 55 | deadLetterTemplate.send(deadLetterRecord); 56 | } 57 | 58 | private static boolean isOddNumber(int number) { 59 | return ((number % 2) != 0); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/divider/DividerStream.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.divider; 2 | 3 | import io.opentracing.Span; 4 | import io.opentracing.Tracer; 5 | import io.opentracing.propagation.Format; 6 | import io.opentracing.propagation.TextMap; 7 | import io.opentracing.tag.Tags; 8 | import io.opentracing.util.GlobalTracer; 9 | import org.apache.kafka.common.serialization.Serdes; 10 | import org.apache.kafka.streams.KeyValue; 11 | import org.apache.kafka.streams.StreamsBuilder; 12 | import org.apache.kafka.streams.kstream.*; 13 | import org.apache.kafka.streams.processor.ProcessorContext; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Value; 17 | import org.springframework.context.annotation.Bean; 18 | import org.springframework.context.annotation.Configuration; 19 | 20 | import java.nio.charset.StandardCharsets; 21 | import java.util.Iterator; 22 | import java.util.Map; 23 | 24 | @Configuration 25 | public class DividerStream { 26 | 27 | private static final Logger LOGGER = LoggerFactory.getLogger(DividerStream.class); 28 | private static final String TRACING_COMPONENT_NAME = "java-kafka"; 29 | private static final String TRACING_SERVICE_NAME = "kafka"; 30 | private static final String TRACING_NUMBER_VALUE = "number.value"; 31 | 32 | @Value("${topics.source-topic}") 33 | private String sourceTopic; 34 | @Value("${topics.target-topic}") 35 | private String targetTopic; 36 | 37 | private final DividerMapper dividerMapper; 38 | 39 | public DividerStream(DividerMapper dividerMapper) { 40 | this.dividerMapper = dividerMapper; 41 | } 42 | 43 | @Bean 44 | public KStream numberStream(StreamsBuilder streamsBuilder) { 45 | KStream stream = streamsBuilder 46 | /* create stream of string numbers */ 47 | .stream(sourceTopic, Consumed.with(Serdes.String(), Serdes.String())) 48 | /* log record received */ 49 | .peek((key, value) -> LOGGER.info("{}: value={}", sourceTopic, value)) 50 | /* start jaeger trace */ 51 | .transform(tracingTransformerSupplier()) 52 | /* map to even integers */ 53 | .map(dividerMapper::map) 54 | /* log record to send */ 55 | .peek(((key, value) -> LOGGER.info("{}: value={}", targetTopic, value))) 56 | /* filter nulls coming from map */ 57 | .filter(((key, value) -> value != null)); 58 | 59 | /* send even integers to target topic */ 60 | stream.to(targetTopic, Produced.with(Serdes.String(), Serdes.Integer())); 61 | return stream; 62 | } 63 | 64 | private TransformerSupplier> tracingTransformerSupplier() { 65 | return new TransformerSupplier>() { 66 | public Transformer> get() { 67 | return new Transformer>() { 68 | 69 | private ProcessorContext context; 70 | 71 | @Override 72 | public void init(ProcessorContext context) { 73 | this.context = context; 74 | } 75 | 76 | @Override 77 | public KeyValue transform(String key, String value) { 78 | if (value == null || value.isEmpty()) { 79 | return KeyValue.pair(key, null); 80 | } 81 | 82 | injectFirstKafkaConsumerSpan(value, context); 83 | 84 | return KeyValue.pair(key, new ValueWithHeaders(value, context.headers())); 85 | } 86 | 87 | @Override 88 | public void close() { 89 | } 90 | }; 91 | } 92 | }; 93 | } 94 | 95 | /** 96 | * {@link io.opentracing.contrib.kafka.TracingKafkaConsumer} only builds and injects a span when there is a parent 97 | * context. This is the first consumer and the beginning of our trace (i.e. there is no parent) so we are building 98 | * and injecting the first span manually. For more context, see the method "buildAndFinishChildSpan" in 99 | * {@link io.opentracing.contrib.kafka.TracingKafkaUtils}. 100 | */ 101 | private void injectFirstKafkaConsumerSpan(String number, ProcessorContext context) { 102 | Tracer tracer = GlobalTracer.get(); 103 | Tracer.SpanBuilder spanBuilder = tracer.buildSpan("receive") 104 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER); 105 | 106 | Span span = spanBuilder.start(); 107 | Tags.COMPONENT.set(span, TRACING_COMPONENT_NAME); 108 | Tags.PEER_SERVICE.set(span, TRACING_SERVICE_NAME); 109 | span.setTag("partition", context.partition()); 110 | span.setTag("topic", context.topic()); 111 | span.setTag("offset", context.offset()); 112 | /* add the number (aka the first consumer record value) as a span tag */ 113 | span.setTag(TRACING_NUMBER_VALUE, number); 114 | span.finish(); 115 | 116 | TextMap headersMapInjectAdapter = new TextMap() { 117 | @Override 118 | public Iterator> iterator() { 119 | throw new UnsupportedOperationException("iterator should never be used with Tracer.inject()"); 120 | } 121 | 122 | @Override 123 | public void put(String key, String value) { 124 | context.headers().add(key, value.getBytes(StandardCharsets.UTF_8)); 125 | } 126 | }; 127 | tracer.inject(span.context(), Format.Builtin.TEXT_MAP, headersMapInjectAdapter); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /stream-app/src/main/java/com/github/burkaa01/stream/divider/ValueWithHeaders.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream.divider; 2 | 3 | import org.apache.kafka.common.header.Headers; 4 | 5 | public class ValueWithHeaders { 6 | 7 | private final String value; 8 | private final Headers headers; 9 | 10 | public ValueWithHeaders(String value, Headers headers) { 11 | this.value = value; 12 | this.headers = headers; 13 | } 14 | 15 | public String getValue() { 16 | return value; 17 | } 18 | 19 | public Headers getHeaders() { 20 | return headers; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /stream-app/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: stream-app 3 | kafka: 4 | bootstrap-servers: localhost:9092 5 | consumer: 6 | group-id: stream-app 7 | 8 | jaeger.tracer: 9 | host: localhost 10 | port: 6831 11 | 12 | topics: 13 | source-topic: number-topic 14 | target-topic: even-topic 15 | dead-letter-topic: odd-topic 16 | -------------------------------------------------------------------------------- /stream-app/src/test/java/com/github/burkaa01/stream/StreamApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.stream; 2 | 3 | public class StreamApplicationTests { 4 | } 5 | -------------------------------------------------------------------------------- /stream-app/src/test/resources/test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/stream-app/src/test/resources/test.yml -------------------------------------------------------------------------------- /topic-configuration/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /topic-configuration/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | COPY build/libs/topic-configuration-0.0.1-SNAPSHOT.jar /app.jar 4 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /topic-configuration/README.md: -------------------------------------------------------------------------------- 1 | # topic-configuration 2 | 3 | This is an example of an application that configures Kafka topics. 4 | -------------------------------------------------------------------------------- /topic-configuration/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | group = 'com.github.burkaa01' 19 | version = '0.0.1-SNAPSHOT' 20 | sourceCompatibility = '1.8' 21 | 22 | repositories { 23 | mavenCentral() 24 | maven { 25 | url "http://packages.confluent.io/maven/" 26 | } 27 | } 28 | 29 | dependencies { 30 | // spring 31 | implementation 'org.springframework.boot:spring-boot-starter' 32 | implementation 'org.springframework.kafka:spring-kafka' 33 | 34 | // kafka 35 | implementation "org.apache.kafka:kafka-clients:2.1.0" 36 | } 37 | -------------------------------------------------------------------------------- /topic-configuration/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/topic-configuration/gradle.properties -------------------------------------------------------------------------------- /topic-configuration/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/topic-configuration/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /topic-configuration/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 21 11:38:34 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /topic-configuration/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /topic-configuration/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /topic-configuration/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'topic-configuration' 2 | -------------------------------------------------------------------------------- /topic-configuration/src/main/java/com/github/burkaa01/topic/TopicConfigurationApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.topic; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TopicConfigurationApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TopicConfigurationApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /topic-configuration/src/main/java/com/github/burkaa01/topic/config/TopicConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.topic.config; 2 | 3 | import org.apache.kafka.clients.admin.NewTopic; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class TopicConfiguration { 9 | 10 | @Bean 11 | public NewTopic numberTopic() { 12 | return new NewTopic("number-topic", 1, (short) 1); 13 | } 14 | 15 | @Bean 16 | public NewTopic oddTopic() { 17 | return new NewTopic("odd-topic", 1, (short) 1); 18 | } 19 | 20 | @Bean 21 | public NewTopic evenTopic() { 22 | return new NewTopic("even-topic", 1, (short) 1); 23 | } 24 | 25 | @Bean 26 | public NewTopic sentenceTopic() { 27 | return new NewTopic("sentence-topic", 1, (short) 1); 28 | } 29 | 30 | @Bean 31 | public NewTopic answerTopic() { 32 | return new NewTopic("answer-topic", 1, (short) 1); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /topic-configuration/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: topic-configuration 3 | kafka: 4 | bootstrap-servers: localhost:9092 5 | -------------------------------------------------------------------------------- /topic-configuration/src/test/java/com/github/burkaa01/topic/TopicConfigurationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.burkaa01.topic; 2 | 3 | public class TopicConfigurationApplicationTests { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /topic-configuration/src/test/resources/test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burkaa01/jaeger-tracing-kafka/7f6619651496ae21fe649b759bff664b4e0bb4d7/topic-configuration/src/test/resources/test.yml --------------------------------------------------------------------------------