diff --git a/build/src/main/resources/agent.properties b/build/src/main/resources/agent.properties index 5e65afe82..0d3d66126 100644 --- a/build/src/main/resources/agent.properties +++ b/build/src/main/resources/agent.properties @@ -14,9 +14,16 @@ easeagent.health.readiness.enabled=true #easeagent.progress.forwarded.headers=X-Forwarded-For #easeagent.progress.forwarded.headers=X-Location,X-Mesh-Service-Canary,X-Phone-Os ### -### default tracings reporter configuration +### default tracings configuration ### -observability.tracings.sampledByQPS=100 +# sampledType: +## counting: percentage sampling, sampled limit 0.01 to 1, 1 is always sample, 0 is never sample, 0.1 is ten samples per hundred +## rate_limiting: traces per second, sampled >= 0, 0 is never sample, 10 is max 10 traces per second +## boundary: percentage sampling by traceId, sampled limit 0.0001 to 1, 1 is always sample, 0 is never sample +## if sampled=0.001, when (traceId^random)%10000<=(0.001*10000) sampled +## sampledType must be used with sampled, otherwise the default value is used Sampler.ALWAYS_SAMPLE +observability.tracings.sampledType= +observability.tracings.sampled=1 # get header from response headers then tag to tracing span # format: observability.tracings.tag.response.headers.{key}={value} # support ease mesh @@ -28,15 +35,12 @@ observability.tracings.tag.response.headers.eg.0=X-EG-Circuit-Breaker observability.tracings.tag.response.headers.eg.1=X-EG-Retryer observability.tracings.tag.response.headers.eg.2=X-EG-Rate-Limiter observability.tracings.tag.response.headers.eg.3=X-EG-Time-Limiter - # -------------------- plugin global config --------------------- plugin.observability.global.tracing.enabled=true - plugin.observability.global.metric.enabled=true plugin.observability.global.metric.interval=30 plugin.observability.global.metric.topic=application-metrics plugin.observability.global.metric.url=/application-metrics - ## # if different with reporter.outputServer.appendType, # following options can be used in user config file to override @@ -57,18 +61,13 @@ plugin.integrability.global.redirect.enabled=true # headers see config: easeagent.progress.forwarded.headers.???=??? plugin.integrability.global.forwarded.enabled=true plugin.hook.global.foundation.enabled=true - - plugin.observability.global.log.enabled=true plugin.observability.global.log.topic=application-log plugin.observability.global.log.url=/application-log #plugin.observability.global.log.appendType=console - plugin.observability.global.log.level=INFO plugin.observability.global.log.encoder=LogDataJsonEncoder - #plugin.observability.global.log.encoder.collectMdcKeys= - # support pattern: # "logLevel": "%-5level", # "threadId": "%thread", @@ -79,21 +78,17 @@ plugin.observability.global.log.encoder.logLevel=%-5level plugin.observability.global.log.encoder.threadId=%thread plugin.observability.global.log.encoder.location=%logger{36} plugin.observability.global.log.encoder.message=%msg%n%xEx{3} - # # -------------------- access --------------------- ## access: servlet and spring gateway plugin.observability.access.log.encoder=AccessLogJsonEncoder # plugin.observability.access.metric.appendType=kafka - #plugin.observability.logback.log.enabled=false #plugin.observability.log4j2.log.enabled=false - # ---------------------------------------------- # if the plugin configuration is consistent with the global namespace, # do not add configuration items not commented out in this default configuration file. # otherwise, they can not be overridden by Global configuration in user's configuration file. - # # -------------------- jvm --------------------- # plugin.observability.jvmGc.metric.enabled=true @@ -147,7 +142,6 @@ plugin.observability.elasticsearch.metric.url=/platform-metrics ## compress.enabled=true, can use md5Dictionary to compress ## compress.enabled=false, use original sql plugin.observability.jdbc.sql.compress.enabled=true - ## md5Dictionary metric # plugin.observability.md5Dictionary.metric.enabled=true # plugin.observability.md5Dictionary.metric.interval=30 @@ -216,7 +210,6 @@ plugin.observability.redis.metric.url=/platform-metrics # plugin.observability.restTemplate.tracing.enabled=true ## httpURLConnection tracing # plugin.observability.httpURLConnection.tracing.enabled=true - # -------------------- service name --------------------- ## add service name to header by name for easemesh. default name: X-Mesh-RPC-Service # plugin.integrability.serviceName.addServiceNameHead.propagate.head=X-Mesh-RPC-Service @@ -248,7 +241,6 @@ plugin.observability.mongodb.metric.url=/platform-metrics plugin.observability.motan.metric.topic=platform-metrics plugin.observability.motan.metric.url=/platform-metrics # plugin.observability.motan.metric.appendType=kafka - # # -------------------- dubbo --------------------- ## dubbo tracing @@ -263,7 +255,6 @@ plugin.observability.motan.metric.url=/platform-metrics #plugin.observability.dubbo.metric.topic=platform-metrics #plugin.observability.dubbo.metric.url=/platform-metrics # plugin.observability.dubbo.metric.appendType=kafka - # -------------------- sofarpc --------------------- # sofarpc tracing # plugin.observability.sofarpc.tracing.enabled=true @@ -277,22 +268,18 @@ plugin.observability.motan.metric.url=/platform-metrics plugin.observability.sofarpc.metric.topic=platform-metrics plugin.observability.sofarpc.metric.url=/platform-metrics # plugin.observability.sofarpc.metric.appendType=kafka - # -------------- output ------------------ ## http/kafka/zipkin server host and port for tracing and metric ###### example ###### ## http: [http|https]://127.0.0.1:8080/report ## kafka: 192.168.1.2:9092, 192.168.1.3:9092, 192.168.1.3:9092 ## zipkin: [http|https]://127.0.0.1:8080/zipkin - reporter.outputServer.bootstrapServer=127.0.0.1:9092 reporter.outputServer.appendType=console reporter.outputServer.timeout=1000 - ## enabled=false: disable output tracing and metric ## enabled=true: output tracing and metric reporter.outputServer.enabled=true - ## username and password for http basic auth reporter.outputServer.username= reporter.outputServer.password= @@ -303,15 +290,12 @@ reporter.outputServer.tls.enable=false reporter.outputServer.tls.key= reporter.outputServer.tls.cert= reporter.outputServer.tls.ca_cert= - - # --- redefine to output properties reporter.log.output.messageMaxBytes=999900 reporter.log.output.reportThread=1 reporter.log.output.queuedMaxSpans=1000 reporter.log.output.queuedMaxSize=1000000 reporter.log.output.messageTimeout=1000 - ## sender.appendType config ## [http] send to http server ## [kafka] send to kafka @@ -320,18 +304,14 @@ reporter.log.output.messageTimeout=1000 ## enabled=true: # reporter.log.sender.enabled=true # reporter.log.sender.url=/application-log - - ## sender.appendType config ## [http] send to http server ## [kafka] send to kafka ## [console] send to console # reporter.tracing.sender.appendType=http # reporter.tracing.sender.appendType=console - ## enabled=true: reporter.tracing.sender.enabled=true - ## url is only used in http ## append to outputServer.bootstrapServer ###### example ###### @@ -344,26 +324,21 @@ reporter.tracing.sender.enabled=true ## reporter.tracing.sender.url=http://127.0.0.10:9090/tracing ## final output url: http://127.0.0.10:9090/tracing reporter.tracing.sender.url=/application-tracing-log - ## topic for kafka use reporter.tracing.sender.topic=application-tracing-log - reporter.tracing.encoder=SpanJsonEncoder - # --- redefine to output properties reporter.tracing.output.messageMaxBytes=999900 reporter.tracing.output.reportThread=1 reporter.tracing.output.queuedMaxSpans=1000 reporter.tracing.output.queuedMaxSize=1000000 reporter.tracing.output.messageTimeout=1000 - ## sender.appendType config ## [http] send to http server ## [metricKafka] send to kafka ## [console] send to console #reporter.metric.sender.appendType=http #reporter.metric.sender.appendType=console - ## url is only used in http ## append to outputServer.bootstrapServer ###### example ###### diff --git a/config/src/main/java/com/megaease/easeagent/config/CompatibilityConversion.java b/config/src/main/java/com/megaease/easeagent/config/CompatibilityConversion.java index 87bb57c87..dd2f9e976 100644 --- a/config/src/main/java/com/megaease/easeagent/config/CompatibilityConversion.java +++ b/config/src/main/java/com/megaease/easeagent/config/CompatibilityConversion.java @@ -63,7 +63,8 @@ public class CompatibilityConversion { TRACING_SKIP = new HashSet<>(); TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_ENABLED); - TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_SAMPLED_BY_QPS); + TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_SAMPLED_TYPE); + TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_SAMPLED); TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_OUTPUT); TRACING_SKIP.add(ConfigConst.Observability.KEY_COMM_TAG); diff --git a/config/src/test/java/com/megaease/easeagent/config/CompatibilityConversionTest.java b/config/src/test/java/com/megaease/easeagent/config/CompatibilityConversionTest.java index 8454bd420..d65c6dd9d 100644 --- a/config/src/test/java/com/megaease/easeagent/config/CompatibilityConversionTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/CompatibilityConversionTest.java @@ -71,9 +71,13 @@ public void transform() { assertEquals("true", newMap.get("observability.metrics.jvmGc.enabled")); - newMap = CompatibilityConversion.transform(Collections.singletonMap("observability.tracings.sampledByQPS", "100")); + newMap = CompatibilityConversion.transform(Collections.singletonMap("observability.tracings.sampledType", "counting")); assertEquals(1, newMap.size()); - assertEquals("100", newMap.get("observability.tracings.sampledByQPS")); + assertEquals("counting", newMap.get("observability.tracings.sampledType")); + + newMap = CompatibilityConversion.transform(Collections.singletonMap("observability.tracings.sampled", "100")); + assertEquals(1, newMap.size()); + assertEquals("100", newMap.get("observability.tracings.sampled")); newMap = CompatibilityConversion.transform(Collections.singletonMap("observability.tracings.output.enabled", "true")); diff --git a/config/src/test/resources/agent.properties b/config/src/test/resources/agent.properties index 259638a06..66c01971e 100644 --- a/config/src/test/resources/agent.properties +++ b/config/src/test/resources/agent.properties @@ -19,7 +19,14 @@ easeagent.health.readiness.enabled=true ### ### default tracings reporter configuration ### -observability.tracings.sampledByQPS=100 +# sampledType: +## counting: percentage sampling, sampled limit 0.01 to 1, 1 is always sample, 0 is never sample, 0.1 is ten samples per hundred +## rate_limiting: traces per second, sampled >= 0, 0 is never sample, 10 is max 10 traces per second +## boundary: percentage sampling by traceId, sampled limit 0.0001 to 1, 1 is always sample, 0 is never sample +## if sampled=0.001, when (traceId^random)%10000<=(0.001*10000) sampled +## sampledType must be used with sampled, otherwise the default value is used Sampler.ALWAYS_SAMPLE +observability.tracings.sampledType= +observability.tracings.sampled=1 # get header from response headers then tag to tracing span # format: observability.tracings.tag.response.headers.{key}={value} # support ease mesh diff --git a/config/src/test/resources/agent.yaml b/config/src/test/resources/agent.yaml index 7cfd8acd1..10256cf5c 100644 --- a/config/src/test/resources/agent.yaml +++ b/config/src/test/resources/agent.yaml @@ -26,6 +26,13 @@ easeagent: ### ### default tracings reporter configuration ### +# sampledType: +## counting: percentage sampling, sampled limit 0.01 to 1, 1 is always sample, 0 is never sample, 0.1 is ten samples per hundred +## rate_limiting: traces per second, sampled >= 0, 0 is never sample, 10 is max 10 traces per second +## boundary: percentage sampling by traceId, sampled limit 0.0001 to 1, 1 is always sample, 0 is never sample +## if sampled=0.001, when (traceId^random)%10000<=(0.001*10000) sampled +## sampledType must be used with sampled, otherwise the default value is used Sampler.ALWAYS_SAMPLE +# # get header from response headers then tag to tracing span # format: observability.tracings.tag.response.headers.{key}={value} # support ease mesh @@ -35,7 +42,8 @@ easeagent: # X-EG-Time-Limiter observability: tracings: - sampledByQPS: 100 + sampledType: "" + sampled: 1 tag: response: headers: diff --git a/doc/user-manual.md b/doc/user-manual.md index cb8c5b057..bea1fe01e 100644 --- a/doc/user-manual.md +++ b/doc/user-manual.md @@ -184,6 +184,23 @@ plugin enabled config: [Enabled](#forwarded-headers-plugin-enabled) ##### Tracing config +Easeagent supports the original sampling model of zipkin. Currently, there are three types of models supported: `counting`, `rate_limiting`, and `boundary`. + +Use the configuration control: `observability.tracings.sampledType` + +1. `counting`: percentage sampling, sampled limit 0.01 to 1, 1 is always sample, 0 is never sample, 0.1 is ten samples per hundred +2. `rate_limiting`: traces per second, sampled >= 0, 0 is never sample, 10 is max 10 traces per second +3. `boundary`: percentage sampling by traceId, sampled limit 0.0001 to 1, 1 is always sample, 0 is never sample. + if sampled=0.001, when (traceId^random)%10000<=(0.001*10000) sampled + +sampledType must be used with sampled, otherwise the default value is used Sampler.ALWAYS_SAMPLE + +Config format: +```properties +observability.tracings.sampledType=counting +observability.tracings.sampled=0.01 +``` + Easeagent will grab the header from the response of the process, and put the name and value of the header as a tag in the Span of Tracing. Config format: diff --git a/plugin-api/src/main/java/com/megaease/easeagent/plugin/api/config/ConfigConst.java b/plugin-api/src/main/java/com/megaease/easeagent/plugin/api/config/ConfigConst.java index b741cd73e..6fd10a9d9 100644 --- a/plugin-api/src/main/java/com/megaease/easeagent/plugin/api/config/ConfigConst.java +++ b/plugin-api/src/main/java/com/megaease/easeagent/plugin/api/config/ConfigConst.java @@ -66,7 +66,8 @@ static String extractHeaderName(String full) { interface Observability { String KEY_COMM_ENABLED = "enabled"; - String KEY_COMM_SAMPLED_BY_QPS = "sampledByQPS"; + String KEY_COMM_SAMPLED_TYPE = "sampledType"; + String KEY_COMM_SAMPLED = "sampled"; String KEY_COMM_OUTPUT = "output"; String KEY_COMM_TAG = "tag"; String KEY_COMM_SERVICE_PREFIX = "servicePrefix"; @@ -95,8 +96,8 @@ interface Observability { String METRICS_ENABLED = join(METRICS, "enabled"); String TRACE_ENABLED = join(TRACE, "enabled"); - String TRACE_SAMPLED_BY_QPS = join(TRACE, KEY_COMM_SAMPLED_BY_QPS); - + String TRACE_SAMPLED_TYPE = join(TRACE, KEY_COMM_SAMPLED_TYPE); + String TRACE_SAMPLED = join(TRACE, KEY_COMM_SAMPLED); String TRACE_OUTPUT = join(TRACE, KEY_COMM_OUTPUT); String TRACE_OUTPUT_ENABLED = join(TRACE_OUTPUT, "enabled"); String TRACE_OUTPUT_TOPIC = join(TRACE_OUTPUT, "topic"); diff --git a/zipkin/src/main/java/com/megaease/easeagent/zipkin/TracingProviderImpl.java b/zipkin/src/main/java/com/megaease/easeagent/zipkin/TracingProviderImpl.java index 649df0269..972c49ba4 100644 --- a/zipkin/src/main/java/com/megaease/easeagent/zipkin/TracingProviderImpl.java +++ b/zipkin/src/main/java/com/megaease/easeagent/zipkin/TracingProviderImpl.java @@ -19,9 +19,14 @@ import brave.Tracing; import brave.propagation.ThreadLocalCurrentTraceContext; +import brave.sampler.BoundarySampler; import brave.sampler.CountingSampler; +import brave.sampler.RateLimitingSampler; +import brave.sampler.Sampler; import com.megaease.easeagent.config.AutoRefreshConfigItem; import com.megaease.easeagent.config.ConfigAware; +import com.megaease.easeagent.log4j2.Logger; +import com.megaease.easeagent.log4j2.LoggerFactory; import com.megaease.easeagent.plugin.annotation.Injection; import com.megaease.easeagent.plugin.api.config.Config; import com.megaease.easeagent.plugin.api.config.ConfigConst; @@ -30,10 +35,9 @@ import com.megaease.easeagent.plugin.api.trace.TracingSupplier; import com.megaease.easeagent.plugin.bean.AgentInitializingBean; import com.megaease.easeagent.plugin.bean.BeanProvider; -import com.megaease.easeagent.plugin.enums.Order; +import com.megaease.easeagent.plugin.report.AgentReport; import com.megaease.easeagent.plugin.report.tracing.ReportSpan; import com.megaease.easeagent.plugin.utils.AdditionalAttributes; -import com.megaease.easeagent.plugin.report.AgentReport; import com.megaease.easeagent.report.AgentReportAware; import com.megaease.easeagent.zipkin.impl.TracingImpl; import com.megaease.easeagent.zipkin.logging.AgentMDCScopeDecorator; @@ -41,7 +45,12 @@ import zipkin2.reporter.brave.ConvertZipkinSpanHandler; public class TracingProviderImpl implements BeanProvider, AgentReportAware, ConfigAware, AgentInitializingBean, TracingProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(TracingProviderImpl.class); private static final String ENV_ZIPKIN_SERVER_URL = "ZIPKIN_SERVER_URL"; + + public static final String SAMPLER_TYPE_COUNTING = "counting"; + public static final String SAMPLER_TYPE_RATE_LIMITING = "rate_limiting"; + public static final String SAMPLER_TYPE_BOUNDARY = "boundary"; private Tracing tracing; private volatile ITracing iTracing; private AgentReport agentReport; @@ -74,7 +83,7 @@ public void afterPropertiesSet() { this.tracing = Tracing.newBuilder() .localServiceName(getServiceName()) .traceId128Bit(false) - .sampler(CountingSampler.create(1)) + .sampler(getSampler()) .addSpanHandler(new CustomTagsSpanHandler(this::getServiceName, AdditionalAttributes.getHostName())) .addSpanHandler(ConvertZipkinSpanHandler .builder(reporter) @@ -86,6 +95,33 @@ public void afterPropertiesSet() { } + protected Sampler getSampler() { + String sampledType = this.config.getString(ConfigConst.Observability.TRACE_SAMPLED_TYPE); + if (sampledType == null) { + return Sampler.ALWAYS_SAMPLE; + } + Double probability = this.config.getDouble(ConfigConst.Observability.TRACE_SAMPLED); + if (probability == null) { + return Sampler.ALWAYS_SAMPLE; + } + try { + switch (sampledType) { + case SAMPLER_TYPE_COUNTING: + return CountingSampler.create(probability.floatValue()); + case SAMPLER_TYPE_RATE_LIMITING: + return RateLimitingSampler.create(probability.intValue()); + case SAMPLER_TYPE_BOUNDARY: + return BoundarySampler.create(probability.floatValue()); + default: + return Sampler.ALWAYS_SAMPLE; + } + } catch (IllegalArgumentException e) { + LOGGER.warn("observability.tracings.sampled error, use Sampler.ALWAYS_SAMPLE for.", e.getMessage()); + return Sampler.ALWAYS_SAMPLE; + } + } + + @Injection.Bean public Tracing tracing() { return tracing; diff --git a/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/RequestContextImpl.java b/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/RequestContextImpl.java index 863e1d633..83da6ccc9 100644 --- a/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/RequestContextImpl.java +++ b/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/RequestContextImpl.java @@ -38,7 +38,7 @@ public RequestContextImpl(Span span, Scope scope, AsyncRequest asyncRequest) { @Override public boolean isNoop() { - return false; + return span.isNoop(); } @Override diff --git a/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/TracingImpl.java b/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/TracingImpl.java index f19717edc..b20c0b63a 100644 --- a/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/TracingImpl.java +++ b/zipkin/src/main/java/com/megaease/easeagent/zipkin/impl/TracingImpl.java @@ -175,9 +175,6 @@ public RequestContext serverReceive(Request request) { span = tracing.tracer().newChild(maybeParent); } - if (span.isNoop()) { - return NoOpContext.NO_OP_PROGRESS_CONTEXT; - } setInfo(span, request); AsyncRequest asyncRequest = new AsyncRequest(request); defaultZipkinInjector.inject(span.context(), asyncRequest); diff --git a/zipkin/src/test/java/com/megaease/easeagent/zipkin/TracingProviderImplTest.java b/zipkin/src/test/java/com/megaease/easeagent/zipkin/TracingProviderImplTest.java index cea36a0af..2d0050346 100644 --- a/zipkin/src/test/java/com/megaease/easeagent/zipkin/TracingProviderImplTest.java +++ b/zipkin/src/test/java/com/megaease/easeagent/zipkin/TracingProviderImplTest.java @@ -17,9 +17,30 @@ package com.megaease.easeagent.zipkin; +import brave.Tracing; +import brave.handler.MutableSpan; +import brave.propagation.TraceContext; +import brave.sampler.BoundarySampler; +import brave.sampler.CountingSampler; +import brave.sampler.RateLimitingSampler; +import brave.sampler.Sampler; +import com.megaease.easeagent.config.GlobalConfigs; +import com.megaease.easeagent.mock.report.MockReport; +import com.megaease.easeagent.plugin.api.config.Config; +import com.megaease.easeagent.plugin.api.context.RequestContext; +import com.megaease.easeagent.plugin.api.trace.ITracing; +import com.megaease.easeagent.plugin.api.trace.Scope; +import com.megaease.easeagent.plugin.api.trace.Span; import com.megaease.easeagent.plugin.api.trace.TracingSupplier; +import com.megaease.easeagent.plugin.field.AgentFieldReflectAccessor; +import com.megaease.easeagent.zipkin.impl.RequestMock; +import com.megaease.easeagent.zipkin.impl.SpanImpl; +import com.megaease.easeagent.zipkin.impl.TracingImpl; import org.junit.Test; +import java.util.HashMap; +import java.util.Map; + import static org.junit.Assert.*; public class TracingProviderImplTest { @@ -53,4 +74,147 @@ public void tracing() { public void tracingSupplier() { afterPropertiesSet(); } + + @Test + public void getSampler() { + TracingProviderImpl tracingProvider = new TracingProviderImpl(); + { + Map initConfigs = new HashMap<>(); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertSame(sampler, Sampler.ALWAYS_SAMPLE); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_COUNTING); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertSame(sampler, Sampler.ALWAYS_SAMPLE); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", "error"); + initConfigs.put("observability.tracings.sampled", "1"); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertSame(sampler, Sampler.ALWAYS_SAMPLE); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_COUNTING); + initConfigs.put("observability.tracings.sampled", "10"); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertSame(sampler, Sampler.ALWAYS_SAMPLE); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_COUNTING); + initConfigs.put("observability.tracings.sampled", "0.1"); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertTrue(sampler instanceof CountingSampler); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_RATE_LIMITING); + initConfigs.put("observability.tracings.sampled", "10"); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertTrue(sampler instanceof RateLimitingSampler); + } + { + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_BOUNDARY); + initConfigs.put("observability.tracings.sampled", "0.0001"); + Config config = new GlobalConfigs(initConfigs); + tracingProvider.setConfig(config); + Sampler sampler = tracingProvider.getSampler(); + assertTrue(sampler instanceof BoundarySampler); + } + } + + @Test + public void testCountingSampler() throws InterruptedException { + String name = "test_name"; + Map initConfigs = new HashMap<>(); + initConfigs.put("observability.tracings.sampledType", TracingProviderImpl.SAMPLER_TYPE_COUNTING); + initConfigs.put("observability.tracings.sampled", "0.01"); + initConfigs.put("name", "test_name"); + Config config = new GlobalConfigs(initConfigs); + TracingProviderImpl tracingProvider = new TracingProviderImpl(); + tracingProvider.setConfig(config); + tracingProvider.setAgentReport(MockReport.getAgentReport()); + tracingProvider.afterPropertiesSet(); + Tracing tracing = tracingProvider.tracing(); + ITracing iTracing = TracingImpl.build(() -> null, tracing); + int noopCount = 0; + for (int i = 0; i < 100; i++) { + RequestMock requestMock = new RequestMock().setKind(Span.Kind.SERVER).setName(name); + assertFalse(iTracing.hasCurrentSpan()); + RequestContext requestContext = iTracing.serverReceive(requestMock); + assertTrue(iTracing.hasCurrentSpan()); + boolean isNoop = requestContext.isNoop(); + if (isNoop) { + noopCount++; + } + String id; + if (isNoop) { + TraceContext traceContext = AgentFieldReflectAccessor.getFieldValue(requestContext.span().unwrap(), "context"); + id = traceContext.traceIdString(); + Span span = iTracing.currentSpan(); + assertTrue(span instanceof SpanImpl); + assertTrue(span.isNoop()); + Span nextSpan = iTracing.nextSpan(); + assertTrue(nextSpan instanceof SpanImpl); + assertTrue(nextSpan.isNoop()); + nextSpan.finish(); + } else { + MutableSpan mutableSpan = TracingProviderImplMock.getMutableSpan(requestContext.span()); + assertEquals(brave.Span.Kind.SERVER, mutableSpan.kind()); + assertEquals(name, mutableSpan.name()); + assertNull(mutableSpan.parentId()); + id = mutableSpan.id(); + } + + RequestContext requestContext2 = iTracing.serverReceive(requestMock); + try (Scope scope = requestContext2.scope()) { + assertNotNull(requestContext2.span().parentIdString()); + assertEquals(id, requestContext2.span().parentIdString()); + } + + try (Scope scope = requestContext.scope()) { + assertNull(requestContext.span().parentIdString()); + assertTrue(iTracing.hasCurrentSpan()); + + RequestMock clientRequest = new RequestMock().setKind(Span.Kind.SERVER).setName(name); + RequestContext clientRequestContext = iTracing.clientRequest(clientRequest); + assertEquals(requestContext.span().traceIdString(), clientRequestContext.span().traceIdString()); + assertEquals(requestContext.span().spanIdString(), clientRequestContext.span().parentIdString()); + + Thread thread = new Thread(() -> { + RequestMock serverRequest = new RequestMock().setHeaders(clientRequest.getHeaders()).setKind(Span.Kind.SERVER); + RequestContext serverReceive = iTracing.serverReceive(serverRequest); + try (Scope scope1 = serverReceive.scope()) { + assertNotNull(serverReceive.span().parentIdString()); + assertEquals(clientRequestContext.span().traceIdString(), serverReceive.span().traceIdString()); + assertEquals(clientRequestContext.span().spanIdString(), serverReceive.span().spanIdString()); + assertEquals(clientRequestContext.span().parentIdString(), serverReceive.span().parentIdString()); + } + }); + thread.start(); + thread.join(); + + clientRequestContext.scope().close(); + } + assertFalse(iTracing.hasCurrentSpan()); + } + assertEquals(99, noopCount); + } }