| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.ignite.internal.processors.monitoring.opencensus; |
| |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import io.opencensus.trace.SpanId; |
| import io.opencensus.trace.export.SpanData; |
| import org.apache.ignite.internal.IgniteEx; |
| import org.apache.ignite.spi.tracing.Scope; |
| import org.apache.ignite.internal.processors.tracing.SpanType; |
| import org.apache.ignite.spi.tracing.TracingSpi; |
| import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; |
| import org.apache.ignite.spi.tracing.TracingConfigurationParameters; |
| import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; |
| import org.apache.ignite.transactions.Transaction; |
| import org.junit.Test; |
| |
| import static org.apache.ignite.spi.tracing.Scope.TX; |
| import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_ALWAYS; |
| import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_NEVER; |
| import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; |
| import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; |
| |
| /** |
| * Tests for transaction tracing configuration. |
| */ |
| public class OpenCensusTxTracingConfigurationTest extends AbstractTracingTest { |
| /** {@inheritDoc} */ |
| @Override protected TracingSpi getTracingSpi() { |
| return new OpenCensusTracingSpi(); |
| } |
| |
| /** |
| * Ensure that in case of sampling rate equals to 0.0 (Never) no transactions are traced. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testTxConfigurationSamplingRateNeverPreventsTxTracing() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_NEVER).build()); |
| |
| client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| Set<String> unexpectedTxSpanNames = Arrays.stream(SpanType.values()). |
| filter(spanType -> spanType.scope() == TX). |
| map(SpanType::spanName). |
| collect(Collectors.toSet()); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> unexpectedTxSpanNames.contains(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertTrue(gotSpans.isEmpty()); |
| } |
| |
| /** |
| * Ensure that in case of sampling rate equals to 1.0 (Always) transactions are successfully traced. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testTxConfigurationSamplingRateAlwaysEnablesTxTracing() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); |
| |
| client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertEquals(1, gotSpans.size()); |
| } |
| |
| /** |
| * Ensure that specifying 0 < sapling rate < 1 within TX scope will trace some but not all transactions. |
| * Cause of probability nature of sampling, it's not possible to check that 0.5 sampling rate |
| * will result in exactly half of the transactions being traced. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testTxConfigurationSamplingRateHalfSamplesSomethingAboutHalfTransactions() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(0.5).build()); |
| |
| final int txAmount = 100; |
| |
| for (int i = 0; i < txAmount; i++) |
| client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| // Cause of probability nature of sampling, it's not possible to check that 0.5 sampling rate will end with |
| // 5 sampling transactions out of {@code txAmount}, |
| // so we just check that some and not all transactions were traced. |
| assertTrue(!gotSpans.isEmpty() && gotSpans.size() < txAmount); |
| } |
| |
| |
| /** |
| * Ensure that TX traces doesn't include COMMUNICATION sub-traces in case of empty set of included scopes. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testTxTraceDoesNotIncludeCommunicationTracesInCaseOfEmptyIncludedScopes() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); |
| |
| Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE); |
| |
| client.cache(DEFAULT_CACHE_NAME).put(1, 1); |
| |
| tx.commit(); |
| |
| handler().flush(); |
| |
| SpanId parentSpanId = handler().allSpans() |
| .filter(span -> SpanType.TX_NEAR_PREPARE.spanName().equals(span.getName())) |
| .collect(Collectors.toList()).get(0).getContext().getSpanId(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> parentSpanId.equals(span.getParentSpanId()) && |
| SpanType.COMMUNICATION_SOCKET_WRITE.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertTrue(gotSpans.isEmpty()); |
| } |
| |
| /** |
| * Ensure that TX trace does include COMMUNICATION sub-traces in case of COMMUNICATION scope within the set |
| * of included scopes of the corresponding TX tracing configuration. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testTxTraceIncludesCommunicationTracesInCaseOfCommunicationScopeInTxIncludedScopes() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder(). |
| withSamplingRate(SAMPLING_RATE_ALWAYS). |
| withIncludedScopes(Collections.singleton(Scope.COMMUNICATION)). |
| build()); |
| |
| Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE); |
| |
| client.cache(DEFAULT_CACHE_NAME).put(1, 1); |
| |
| tx.commit(); |
| |
| handler().flush(); |
| |
| SpanId parentSpanId = handler().allSpans() |
| .filter(span -> SpanType.TX_NEAR_PREPARE.spanName().equals(span.getName())) |
| .collect(Collectors.toList()).get(0).getContext().getSpanId(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> parentSpanId.equals(span.getParentSpanId()) && |
| SpanType.COMMUNICATION_SOCKET_WRITE.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertFalse(gotSpans.isEmpty()); |
| } |
| |
| /** |
| * Ensure that label specific configuration is used instead of scope specific if it's possible. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testThatLabelSpecificConfigurationIsUsedWheneverPossible() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| final String txLbToBeTraced = "label1"; |
| |
| final String txLbNotToBeTraced = "label2"; |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).withLabel(txLbToBeTraced).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); |
| |
| client.transactions().withLabel(txLbToBeTraced).txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertEquals(1, gotSpans.size()); |
| |
| // Not to be traced, cause there's neither tracing configuration with given label |
| // nor scope specific tx configuration. In that case default tx tracing configuration will be used that |
| // actually disables tracing. |
| client.transactions().withLabel(txLbNotToBeTraced).txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| // Still only one, previously detected, span is expected. |
| assertEquals(1, gotSpans.size()); |
| } |
| |
| /** |
| * Ensure that scope specific configuration is used if corresponding label specific not found. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testThatScopeSpecificConfigurationIsUsedIfLabelSpecificNotFound() throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.tracingConfiguration().set( |
| new TracingConfigurationCoordinates.Builder(TX).build(), |
| new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); |
| |
| client.transactions().withLabel("label1").txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertEquals(1, gotSpans.size()); |
| } |
| |
| /** |
| * Ensure that default scope specific configuration is used if there's no neither label specif not custom scope specific ones. |
| * Also ensure that by default TX tracing is disabled. |
| * |
| * @throws Exception If Failed. |
| */ |
| @Test |
| public void testThatDefaultConfigurationIsUsedIfScopeSpecificNotFoundAndThatByDefaultTxTracingIsDisabled() |
| throws Exception { |
| IgniteEx client = startGrid("client"); |
| |
| client.transactions().withLabel("label1").txStart(PESSIMISTIC, SERIALIZABLE).commit(); |
| |
| handler().flush(); |
| |
| java.util.List<SpanData> gotSpans = handler().allSpans() |
| .filter(span -> SpanType.TX.spanName().equals(span.getName())) |
| .collect(Collectors.toList()); |
| |
| assertTrue(gotSpans.isEmpty()); |
| } |
| } |