Skip to content

Commit

Permalink
feat: LUMIGO_REDUCED_REDIS_INSTRUMENTATION (#604)
Browse files Browse the repository at this point in the history
  • Loading branch information
eugene-lumigo authored Nov 28, 2024
1 parent bcab1a6 commit 1fc5472
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ The Lumigo OpenTelemetry Distro for Java additionally supports the following con
* `LUMIGO_FILTER_HTTP_ENDPOINTS_REGEX_CLIENT` applies the filter to client spans only. Matching is performed against the following attributes on a span: `url.full`, and `http.url`[^2].
* `LUMIGO_ENABLE_LOGS=true`: Turns on the logging instrumentation to capture log-records, for logging libraries that support open-telemetry (e.g. Logback). By default, the logging instrumentation is disabled.
* `LUMIGO_ENABLE_TRACES=true`: Turns on the tracing instrumentation. By default, the tracing instrumentation is enabled.
* `LUMIGO_REDUCED_MONGO_INSTRUMENTATION=true`: Reduces the amount of data collected by the MongoDB instrumentation, such as not collecting the `db.operation` attribute `isMaster`. By default, the MongoDB instrumentation reduces the amount of data collected.
* `LUMIGO_REDUCED_MONGO_INSTRUMENTATION=true`: Reduces the amount of data collected by the MongoDB [instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/mongo), such as not collecting the `db.operation` attribute `isMaster`. By default, the MongoDB instrumentation reduces the amount of data collected.
* `LUMIGO_REDUCED_REDIS_INSTRUMENTATION=true`: Reduces the amount of data collected by the Redis [instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jedis), such as not collecting the `db.statement` attribute `INFO server`. By default, the Redis instrumentation reduces the amount of data collected.

For more configuration options, see the [Upstream Agent Configuration](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/).

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2023 Lumigo LTD
*
* Licensed 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package io.lumigo.javaagent;

import com.google.auto.service.AutoService;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.contrib.sampler.RuleBasedRoutingSampler;
import io.opentelemetry.contrib.sampler.RuleBasedRoutingSamplerBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.util.logging.Logger;

@AutoService(AutoConfigurationCustomizerProvider.class)
public class RedisSamplingConfigurer implements AutoConfigurationCustomizerProvider {
private static final Logger LOGGER = Logger.getLogger(RedisSamplingConfigurer.class.getName());

public static final String LUMIGO_REDUCED_REDIS_INSTRUMENTATION =
"lumigo.reduced.redis.instrumentation";

@Override
public void customize(AutoConfigurationCustomizer autoConfiguration) {
autoConfiguration.addSamplerCustomizer(RedisSamplingConfigurer::customizeRedisSpans);
}

private static Sampler customizeRedisSpans(
Sampler defaultSampler, ConfigProperties configProperties) {

RuleBasedRoutingSamplerBuilder samplerBuilder =
RuleBasedRoutingSampler.builder(SpanKind.CLIENT, defaultSampler);

String reduceRedisInstrumentation =
configProperties.getString(LUMIGO_REDUCED_REDIS_INSTRUMENTATION);
boolean isReducedRedisInstrumentationEnabled;

if (reduceRedisInstrumentation == null || reduceRedisInstrumentation.isEmpty()) {
isReducedRedisInstrumentationEnabled = true; // Default to true
} else if (reduceRedisInstrumentation.equalsIgnoreCase("true")) {
isReducedRedisInstrumentationEnabled = true;
} else if (reduceRedisInstrumentation.equalsIgnoreCase("false")) {
isReducedRedisInstrumentationEnabled = false;
} else {
LOGGER.warning(
"Invalid value for LUMIGO_REDUCED_REDIS_INSTRUMENTATION: "
+ reduceRedisInstrumentation
+ ". Defaulting to true.");
isReducedRedisInstrumentationEnabled = true;
}

if (isReducedRedisInstrumentationEnabled) {

// Setting the environment variable `LUMIGO_REDUCED_REDIS_INSTRUMENTATION=false` will disable
// this optimization.
LOGGER.finest(
"Lumigo reduces Redis instrumentation. The `db.statement` attribute (e.g., `INFO server`) is excluded by default. Set `LUMIGO_REDUCED_REDIS_INSTRUMENTATION=false` to disable this behavior.");

// Define attribute keys
AttributeKey<String> dbSystemKey = AttributeKey.stringKey("db.system");
AttributeKey<String> dbStatementKey = AttributeKey.stringKey("db.statement");

samplerBuilder.customize(
dbSystemKey,
"redis",
RuleBasedRoutingSampler.builder(SpanKind.CLIENT, defaultSampler)
// have to use regex to match the db.statement attribute, that can be "INFO server" or
// "server", depending on the Redis configuration
.drop(dbStatementKey, "(INFO\\s+)?server")
.build());
}

return samplerBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright 2024 Lumigo LTD
*
* Licensed 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package io.lumigo.javaagent;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.trace.IdGenerator;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
import java.util.Collections;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class RedisSamplingConfiguratorTest extends AbstractSamplingConfiguratorTest {
@AfterEach
public void tearDown() {
System.clearProperty(RedisSamplingConfigurer.LUMIGO_REDUCED_REDIS_INSTRUMENTATION);
}

@Test
public void shouldDropByDefaultInfoServer() {
AutoConfiguredOpenTelemetrySdkBuilder builder = AutoConfiguredOpenTelemetrySdk.builder();

new RedisSamplingConfigurer().customize(builder);
addPropertiesCustomizer(builder);

AutoConfiguredOpenTelemetrySdk sdk = builder.build();

SdkTracerProvider tracerProvider = sdk.getOpenTelemetrySdk().getSdkTracerProvider();
Sampler sampler = tracerProvider.getSampler();

// Test that the default behavior is to drop "INFO server" commands
SamplingResult infoServerResult =
sampler.shouldSample(
Context.root(),
IdGenerator.random().generateTraceId(),
"name",
SpanKind.CLIENT,
Attributes.of(
AttributeKey.stringKey("db.system"), "redis",
AttributeKey.stringKey("db.statement"), "INFO server"),
Collections.emptyList());
Assertions.assertEquals(SamplingResult.drop(), infoServerResult);

// Test that the default behavior is to drop "server" commands
SamplingResult serverResult =
sampler.shouldSample(
Context.root(),
IdGenerator.random().generateTraceId(),
"name",
SpanKind.CLIENT,
Attributes.of(
AttributeKey.stringKey("db.system"), "redis",
AttributeKey.stringKey("db.statement"), "server"),
Collections.emptyList());
Assertions.assertEquals(SamplingResult.drop(), serverResult);
}

@Test
public void shouldNotDropIfFalse() {
System.setProperty(RedisSamplingConfigurer.LUMIGO_REDUCED_REDIS_INSTRUMENTATION, "false");
AutoConfiguredOpenTelemetrySdkBuilder builder = AutoConfiguredOpenTelemetrySdk.builder();

new RedisSamplingConfigurer().customize(builder);
addPropertiesCustomizer(builder);

AutoConfiguredOpenTelemetrySdk sdk = builder.build();

SdkTracerProvider tracerProvider = sdk.getOpenTelemetrySdk().getSdkTracerProvider();
Sampler sampler = tracerProvider.getSampler();

Attributes attributes =
Attributes.of(
AttributeKey.stringKey("db.system"), "redis",
AttributeKey.stringKey("db.statement"), "INFO server");
SamplingResult result =
sampler.shouldSample(
Context.root(),
IdGenerator.random().generateTraceId(),
"name",
SpanKind.CLIENT,
attributes,
Collections.emptyList());
Assertions.assertEquals(SamplingResult.recordAndSample(), result);
}

@Test
public void shouldNotDropIfNotInfo() {
AutoConfiguredOpenTelemetrySdkBuilder builder = AutoConfiguredOpenTelemetrySdk.builder();

new RedisSamplingConfigurer().customize(builder);
addPropertiesCustomizer(builder);

AutoConfiguredOpenTelemetrySdk sdk = builder.build();

SdkTracerProvider tracerProvider = sdk.getOpenTelemetrySdk().getSdkTracerProvider();
Sampler sampler = tracerProvider.getSampler();

Attributes attributes =
Attributes.of(
AttributeKey.stringKey("db.system"), "redis",
AttributeKey.stringKey("db.statement"), "other");
SamplingResult result =
sampler.shouldSample(
Context.root(),
IdGenerator.random().generateTraceId(),
"name",
SpanKind.CLIENT,
attributes,
Collections.emptyList());
Assertions.assertEquals(SamplingResult.recordAndSample(), result);
}
}

0 comments on commit 1fc5472

Please sign in to comment.