Skip to content

Make ThrottlingLogger logging time configurable #7178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ellen-lau opened this issue Mar 5, 2025 · 4 comments
Open

Make ThrottlingLogger logging time configurable #7178

ellen-lau opened this issue Mar 5, 2025 · 4 comments

Comments

@ellen-lau
Copy link

Issue:

Related to this issue in OpenLiberty, when Liberty is unable to connect to the OpenTelemetry Collector the OTel sdk logs messages to indicate that failure. Using the ThrottlingLogger, it logs the message once a minute, which seems like a lot.

Proposed Solution:

Have the ThrottlingLogger logging time be configurable to a specific time interval (to 1 minute, 1 hour, etc).

@jkwatson
Copy link
Contributor

jkwatson commented Mar 6, 2025

How would you imagine configuring this, in general? I'm not opposed to adding this feature to the ThrottlingLogger itself, but how would you then configure that in the SDK?

@gabgg71
Copy link

gabgg71 commented Mar 27, 2025

The code for SDK would look something like this:

// src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpLogRecordExporterProvider.java
//....
public class OtlpLogRecordExporterProvider
    implements ConfigurableLogRecordExporterProvider, AutoConfigureListener {

  private final AtomicReference<MeterProvider> meterProviderRef =
      new AtomicReference<>(MeterProvider.noop());

  @Override
  public LogRecordExporter createExporter(ConfigProperties config) {
    String protocol = OtlpConfigUtil.getOtlpProtocol(DATA_TYPE_LOGS, config);

    if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) {
      OtlpHttpLogRecordExporterBuilder builder = httpBuilder();

      OtlpConfigUtil.configureOtlpExporterBuilder(
          DATA_TYPE_LOGS,
          config,
          builder::setEndpoint,
          builder::addHeader,
          builder::setCompression,
          builder::setTimeout,
          builder::setTrustedCertificates,
          builder::setClientTls,
          builder::setRetryPolicy,
          builder::setMemoryMode,
          builder::setThrottlingLoggerTimeUnit);
      builder.setMeterProvider(meterProviderRef::get);

      return builder.build();
    } else if (protocol.equals(PROTOCOL_GRPC)) {
      OtlpGrpcLogRecordExporterBuilder builder = grpcBuilder();

      OtlpConfigUtil.configureOtlpExporterBuilder(
          DATA_TYPE_LOGS,
          config,
          builder::setEndpoint,
          builder::addHeader,
          builder::setCompression,
          builder::setTimeout,
          builder::setTrustedCertificates,
          builder::setClientTls,
          builder::setRetryPolicy,
          builder::setMemoryMode,
          builder::setThrottlingLoggerTimeUnit);
      builder.setMeterProvider(meterProviderRef::get);

      return builder.build();
    }
    throw new ConfigurationException("Unsupported OTLP logs protocol: " + protocol);
  }
//...
// src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java
//....
public final class OtlpHttpLogRecordExporterBuilder {
//....
public OtlpHttpLogRecordExporterBuilder setThrottlingLoggerTimeUnit(TimeUnit throttlingLoggerTimeUnit) {
    delegate.setThrottlingLoggerTimeUnit(throttlingLoggerTimeUnit);
    return this;
  }
//...
}
// src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java
//....
public final class HttpExporterBuilder<T extends Marshaler>{
private TimeUnit throttlingLoggerTimeUnit = TimeUnit.MINUTES;
//.... 
public HttpExporterBuilder<T> setThrottlingLoggerTimeUnit(TimeUnit throttlingLoggerTimeUnit) {
    this.throttlingLoggerTimeUnit = throttlingLoggerTimeUnit;
    return this;
  }
//...
public HttpExporter<T> build() {
//...

return new HttpExporter<>(
        exporterName,
        type,
        httpSender,
        meterProviderSupplier,
        exportAsJson,
        this.throttlingLoggerTimeUnit);
}
//....
// src/main/java/io/opentelemetry/exporter/internal/http/HttpExporter.java
//....
public final class HttpExporter<T extends Marshaler> {

  private static final Logger internalLogger = Logger.getLogger(HttpExporter.class.getName());

  private final ThrottlingLogger logger;
 //...

  public HttpExporter(
      String exporterName,
      String type,
      HttpSender httpSender,
      Supplier<MeterProvider> meterProviderSupplier,
      boolean exportAsJson,
      TimeUnit throttlingLoggerTimeUnit) {
    this.type = type;
    this.httpSender = httpSender;
    this.exporterMetrics =
        exportAsJson
            ? ExporterMetrics.createHttpJson(exporterName, type, meterProviderSupplier)
            : ExporterMetrics.createHttpProtobuf(exporterName, type, meterProviderSupplier);

    this.logger = new ThrottlingLogger(internalLogger, throttlingLoggerTimeUnit);
  }
//....
// src/main/java/io/opentelemetry/sdk/internal/ThrottlingLogger.java
public class ThrottlingLogger {
  private static final double RATE_LIMIT = 5;
  private static final double THROTTLED_RATE_LIMIT = 1;
  private TimeUnit rateTimeUnit = MINUTES;

  private final Logger delegate;
  private final AtomicBoolean throttled = new AtomicBoolean(false);
  private final RateLimiter fastRateLimiter;
  private final RateLimiter throttledRateLimiter;

  public ThrottlingLogger(Logger delegate) {
    this(delegate, Clock.getDefault());
  }
// new constructor
  public ThrottlingLogger(Logger delegate, TimeUnit rateTimeUnit) {
    this(delegate);
    this.rateTimeUnit = rateTimeUnit;
  }
//...

This would likely require corresponding schema changes OpenTelemetry Configuration repo.

@jkwatson
Copy link
Contributor

The only thing you want to configure is the time unit? Not the interval itself?

@gabgg71
Copy link

gabgg71 commented Apr 2, 2025

You're right, it makes more sense to configure the interval. We can express the other time units just by adjusting the interval or configure both of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants