diff --git a/README.md b/README.md index 079c429f..3d24fb01 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ For publishing data using a producer which is defined for the stream router conf ## Tracing [Open Tracing](https://opentracing.io/docs/overview/) enables to identify the amount of time spent in various stages of the work flow. -Currently, the execution of the handler function can be traced. If the message consumed has the corresponding tracing headers, then the E2E life time of the message from the time of production till the time of consumption can be traced. +Currently, the execution of the handler function is traced. If the message consumed has the corresponding tracing headers, then the E2E life time of the message from the time of production till the time of consumption can be traced. Tracing has been added to the following flows: @@ -212,20 +212,23 @@ Tracing has been added to the following flows: 3. Produce to rabbitmq channel 4. Produce to another kafka topic -By default, tracing is done via [Jaeger](https://www.jaegertracing.io/). The corresponding `:default-tracer-config` has to be set to publish the traces to the desired Jaeger cluster. -To enable custom tracer, a tracer provider function name can be set in `:tracer-provider`. The corresponding function will be executed in runtime to create a tracer. In the event of any errors while executing the custom tracer provider, a Noop tracer will be created. +By default, tracing is done via [Jaeger](https://www.jaegertracing.io/) based on the env configs. Please refer [Jaeger Configuration](https://github.com/jaegertracing/jaeger-client-java/tree/master/jaeger-core#configuration-via-environment) +and [Jaeger Architecture](https://www.jaegertracing.io/docs/1.13/architecture/) to set the respective env variables. +To enable custom tracer, a custom tracer provider function name can be set in `:custom-provider`. The corresponding function will be executed in runtime to create a tracer. In the event of any errors while executing the custom tracer provider, a Noop tracer will be created. To enable tracing, the following config needs to be added to the `config.edn` under `:ziggurat` key. ```clojure :tracer {:enabled [true :bool] - :tracer-provider "" - :default-tracer-config {:jaeger-service-name "test_service" - :jaeger-agent-host "localhost" - :jaeger-agent-port [6831 :int] - :jaeger-reporter-log-spans [true :bool]}} + :custom-provider ""} +``` + +Example Jaeger Env Config: +``` +JAEGER_SERVICE_NAME: "service-name" +JAEGER_AGENT_HOST: "localhost" +JAEGER_AGENT_PORT: 6831 ``` -`:jaeger_service_name` is the operation name for the trace ## Configuration diff --git a/resources/config.test.ci.edn b/resources/config.test.ci.edn index 56a424ac..f29fb457 100644 --- a/resources/config.test.ci.edn +++ b/resources/config.test.ci.edn @@ -51,9 +51,5 @@ :retry {:count [5 :int] :enabled [true :bool]}}}}} :tracer {:enabled [true :bool] - :tracer-provider "" - :default-tracer-config {:jaeger-service-name "test_service" - :jaeger-agent-host "localhost" - :jaeger-agent-port [6831 :int] - :jaeger-reporter-log-spans [true :bool]}}}} + :tracer-provider ""}}} diff --git a/resources/config.test.edn b/resources/config.test.edn index 8ce5c7a0..1e9933b2 100644 --- a/resources/config.test.edn +++ b/resources/config.test.edn @@ -50,9 +50,5 @@ :channels {:channel-1 {:worker-count [10 :int] :retry {:count [5 :int] :enabled [true :bool]}}}}} - :tracer {:enabled [true :bool] - :tracer-provider "" - :default-tracer-config {:jaeger-service-name "test_service" - :jaeger-agent-host "localhost" - :jaeger-agent-port [6831 :int] - :jaeger-reporter-log-spans [true :bool]}}}} + :tracer {:enabled [true :bool] + :custom-provider ""}}} diff --git a/src/ziggurat/tracer.clj b/src/ziggurat/tracer.clj index 6df8ff18..7dff438c 100644 --- a/src/ziggurat/tracer.clj +++ b/src/ziggurat/tracer.clj @@ -1,32 +1,82 @@ (ns ziggurat.tracer + "This namespace creates a [tracer](https://opentracing.io/docs/overview/tracers/) + that can be used to trace the various stages of the application workflow. + + The following flows are traced: + 1. Normal basic consume + 2. Retry via rabbitmq + 3. Produce to rabbitmq channel + 4. Produce to another kafka topic + + At the time of initialization, an instance of `io.opentracing Tracer` + is created based on the configuration. + + - If tracer is disabled, then a `NoopTracer` is created, + which will basically do nothing. + + - If tracer is enabled, then by default a [Jaeger](https://www.jaegertracing.io/) + tracer will be created based on the environment variables. Please refer + [Jaeger Configuration](https://github.com/jaegertracing/jaeger-client-java/tree/master/jaeger-core#configuration-via-environment) + and [Jaeger Architecture](https://www.jaegertracing.io/docs/1.13/architecture/) + to set the respective env variables. + + Example Jaeger Env Config: + ` + JAEGER_SERVICE_NAME: \"service-name\" + JAEGER_AGENT_HOST: \"localhost\" + JAEGER_AGENT_PORT: 6831 + ` + + - Custom tracer can be created by passing the name of a custom tracer + provider function as `:custom-provider`.The corresponding function + will be executed to create the tracer. + + In the event of any errors, a NoopTracer will be created + + Example tracer configuration: + + ` + :tracer {:enabled [true :bool]\n + :custom-provider \"\"} + ` + + Usage: + ` + In `ziggurat.streams/traced-handler-fn`, around the execution of the handler function, + a span is started, activated and finished. If there are trace-id headers in the kafka message, + this span will be tied to the same trace. If not, a new trace will be started. + + Any part of the handler function execution can be traced as a child span of this activated parent span. + Please refer to the [doc](https://github.com/opentracing/opentracing-java#starting-a-new-span) + to understand how to create child spans. + + The trace ids are propagated to rabbitmq using `io.opentracing.contrib.rabbitmq.TracingConnection`. + Hence rabbitmq flows are also traced. + + The trace ids are propagated back to kafka using `io.opentracing.contrib.kafka.TracingKafkaProducer`. + Hence push back to kafka flow is traced. + `" (:require [mount.core :refer [defstate]] [ziggurat.config :refer [ziggurat-config]] [clojure.tools.logging :as log]) - (:import [io.jaegertracing Configuration Configuration$ReporterConfiguration Configuration$SenderConfiguration] + (:import [io.jaegertracing Configuration] [io.opentracing.noop NoopTracerFactory] [io.opentracing Tracer])) -(defn- default-tracer-provider [{:keys [jaeger-service-name jaeger-agent-host jaeger-agent-port jaeger-reporter-log-spans]}] - (let [sender-configuration (-> (Configuration$SenderConfiguration.) - (.withAgentHost jaeger-agent-host) - (.withAgentPort (int jaeger-agent-port))) - reporter-configuration (-> (Configuration$ReporterConfiguration.) - (.withLogSpans jaeger-reporter-log-spans) - (.withSender sender-configuration)) - configuration (.withTraceId128Bit (Configuration. jaeger-service-name) true)] - (.getTracer (.withReporter configuration reporter-configuration)))) +(defn default-tracer-provider [] + (.getTracer (Configuration/fromEnv))) (defn create-tracer [] (try (let [tracer-config (:tracer (ziggurat-config)) - tracer-provider (:tracer-provider tracer-config)] + custom-provider (:custom-provider tracer-config)] (if (or (nil? tracer-config) (false? (:enabled tracer-config))) (NoopTracerFactory/create) - (if (or (nil? tracer-provider) (empty? tracer-provider)) - (default-tracer-provider (:default-tracer-config tracer-config)) + (if (or (nil? custom-provider) (empty? custom-provider)) + (default-tracer-provider) - (let [custom-tracer (apply (resolve (symbol tracer-provider)) [])] + (let [custom-tracer (apply (resolve (symbol custom-provider)) [])] (if-not (instance? Tracer custom-tracer) (throw (RuntimeException. "Tracer provider did not return a valid tracer")) custom-tracer))))) diff --git a/test/ziggurat/tracer_test.clj b/test/ziggurat/tracer_test.clj index 4fc1c9fe..2af7f5f9 100644 --- a/test/ziggurat/tracer_test.clj +++ b/test/ziggurat/tracer_test.clj @@ -4,7 +4,8 @@ [ziggurat.config :refer [ziggurat-config]] [ziggurat.fixtures :as fix] [ziggurat.tracer :as tracer]) - (:import [io.opentracing.mock MockTracer])) + (:import [io.opentracing.mock MockTracer] + (io.jaegertracing.internal JaegerTracer$Builder))) (use-fixtures :once fix/silence-logging) @@ -14,14 +15,16 @@ (deftest mount-tracer-test (testing "should start JaegerTracer when tracer is enabled and tracer provider is empty" (fix/mount-config) - (mount/start (mount/only [#'tracer/tracer])) - (is (= "JaegerTracer" (.getSimpleName (.getClass tracer/tracer)))) + (with-redefs [tracer/default-tracer-provider (fn [] (.build (JaegerTracer$Builder. "test")))] + (mount/start (mount/only [#'tracer/tracer])) + (is (= "JaegerTracer" (.getSimpleName (.getClass tracer/tracer))))) (mount/stop)) (testing "should start JaegerTracer when tracer is enabled and tracer provider is nil" (fix/mount-config) - (mount/start (mount/only [#'tracer/tracer])) - (is (= "JaegerTracer" (.getSimpleName (.getClass tracer/tracer)))) + (with-redefs [tracer/default-tracer-provider (fn [] (.build (JaegerTracer$Builder. "test")))] + (mount/start (mount/only [#'tracer/tracer])) + (is (= "JaegerTracer" (.getSimpleName (.getClass tracer/tracer))))) (mount/stop)) (testing "should execute create custom tracer when tracer is enabled and tracer provider is set"