Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 8 additions & 42 deletions plugins/telemetry-otel/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ dependencies {
api "io.opentelemetry:opentelemetry-sdk-logs:${versions.opentelemetry}-alpha"
api "io.opentelemetry:opentelemetry-api-logs:${versions.opentelemetry}-alpha"

// TODO add license files
// exporters
api "io.opentelemetry:opentelemetry-exporter-common:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-exporter-otlp:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-exporter-otlp-common:${versions.opentelemetry}"
api "io.opentelemetry:opentelemetry-extension-incubator:${versions.opentelemetry}-alpha"

api "com.squareup.okhttp3:okhttp:4.10.0"
api "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}"
api("com.squareup.okhttp3:okhttp:${versions.okhttp}")
api 'org.jetbrains.kotlin:kotlin-stdlib:1.6.20'
api 'com.squareup.okio:okio-jvm:3.0.0'
}

Expand All @@ -52,52 +53,17 @@ thirdPartyAudit {
)

ignoreMissingClasses(
'android.net.http.X509TrustManagerExtensions',
'android.net.ssl.SSLSockets',
'android.os.Build$VERSION',
'android.security.NetworkSecurityPolicy',
'android.util.Log',
'com.google.common.io.ByteStreams',
'com.google.common.util.concurrent.FutureCallback',
'com.google.common.util.concurrent.Futures',
'com.google.common.util.concurrent.ListenableFuture',
'com.google.common.util.concurrent.MoreExecutors',
'io.grpc.CallOptions',
'io.grpc.Channel',
'io.grpc.ClientInterceptor',
'io.grpc.ClientInterceptors',
'io.grpc.Codec',
'io.grpc.Codec$Identity',
'io.grpc.Drainable',
'io.grpc.KnownLength',
'io.grpc.ManagedChannel',
'io.grpc.Metadata',
'io.grpc.Metadata$Key',
'io.grpc.MethodDescriptor',
'io.grpc.MethodDescriptor$Builder',
'io.grpc.MethodDescriptor$Marshaller',
'io.grpc.MethodDescriptor$MethodType',
'io.grpc.Status',
'io.grpc.Status$Code',
'io.grpc.stub.AbstractFutureStub',
'io.grpc.stub.AbstractStub',
'io.grpc.stub.ClientCalls',
'io.grpc.stub.MetadataUtils',
'io.opentelemetry.api.events.EventEmitter',
'io.opentelemetry.api.events.EventEmitterBuilder',
'io.opentelemetry.api.events.EventEmitterProvider',
'io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder',
'io.opentelemetry.extension.incubator.metrics.ExtendedLongHistogramBuilder',
'io.opentelemetry.extension.incubator.metrics.HistogramAdviceConfigurer',
'io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties',
'io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider',
'io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider',
'io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider',
'org.bouncycastle.jsse.BCSSLParameters',
'org.bouncycastle.jsse.BCSSLSocket',
'org.conscrypt.Conscrypt',
'org.conscrypt.Conscrypt$Version',
'org.conscrypt.ConscryptHostnameVerifier',
'org.openjsse.javax.net.ssl.SSLParameters',
'org.openjsse.javax.net.ssl.SSLSocket'
)
'io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider'
)
}

tasks.named("bundlePlugin").configure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@
import org.opensearch.common.settings.Settings;
import org.opensearch.plugins.Plugin;
import org.opensearch.plugins.TelemetryPlugin;
import org.opensearch.telemetry.diagnostics.jmx.JMXMetricsObserverThread;
import org.opensearch.telemetry.diagnostics.jmx.JMXOTelMetricEmitter;
import org.opensearch.telemetry.diagnostics.jmx.JMXThreadResourceRecorder;
import org.opensearch.telemetry.tracing.listeners.TraceEventListener;
import org.opensearch.telemetry.metrics.OTelMetricsTelemetry;
import org.opensearch.telemetry.tracing.OTelResourceProvider;
import org.opensearch.telemetry.tracing.OTelTelemetry;
import org.opensearch.telemetry.tracing.OTelTracingTelemetry;
import org.opensearch.telemetry.diagnostics.DiagnosticsEventListener;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
Expand All @@ -46,8 +53,7 @@ public List<Setting<?>> getSettings() {
OTelTelemetrySettings.TRACER_EXPORTER_DELAY_SETTING,
OTelTelemetrySettings.TRACER_EXPORTER_MAX_QUEUE_SIZE_SETTING,
OTelTelemetrySettings.OTEL_TRACER_SPAN_EXPORTER_CLASS_SETTING,
OTelTelemetrySettings.OTEL_TRACER_METRIC_EXPORTER_NAME_SETTING,
OTelTelemetrySettings.OTEL_TRACER_METRIC_READER_INTERVAL_SETTING
OTelTelemetrySettings.OTEL_TRACER_METRIC_EXPORTER_NAME_SETTING
);
}

Expand All @@ -56,21 +62,32 @@ public Optional<Telemetry> getTelemetry(TelemetrySettings settings) {
return Optional.of(telemetry());
}

@Override
public Map<String, TraceEventListener> getTraceEventListeners(Telemetry telemetry) {
if (!ensureOpenTelemetry(telemetry)) {
return Collections.emptyMap();
}
OpenTelemetry openTelemetry = ((OTelMetricsTelemetry)telemetry.getMetricsTelemetry()).getTelemetry();
return Map.of("ThreadDiagnosticsTraceEventListener", new DiagnosticsEventListener(
new JMXThreadResourceRecorder(new JMXMetricsObserverThread()),
JMXOTelMetricEmitter.getInstance(openTelemetry)
));
}

@Override
public String getName() {
return OTEL_TRACER_NAME;
}

private Telemetry telemetry() {
OpenTelemetry openTelemetry = OTelResourceProvider.get(settings);
return new OTelTelemetry(new OTelTracingTelemetry(openTelemetry), new OTelMetricsTelemetry(openTelemetry));
return new OTelTelemetry(new OTelTracingTelemetry(openTelemetry),
new OTelMetricsTelemetry(openTelemetry));
}

private boolean ensureOpenTelemetry(Telemetry telemetry) {
return (telemetry != null
&& telemetry.getMetricsTelemetry() != null
&& telemetry instanceof OTelTelemetry
&& telemetry.getMetricsTelemetry() instanceof OTelMetricsTelemetry);
return (telemetry != null && telemetry.getMetricsTelemetry() != null
&& telemetry instanceof OTelTelemetry && telemetry.getMetricsTelemetry() instanceof OTelMetricsTelemetry);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,4 @@ private OTelTelemetrySettings() {}
Setting.Property.NodeScope,
Setting.Property.Final
);

/**
* Metric reader interval
*/
public static final Setting<TimeValue> OTEL_TRACER_METRIC_READER_INTERVAL_SETTING = Setting.timeSetting(
"telemetry.otel.tracer.metric.reader.interval",
TimeValue.timeValueSeconds(60),
Setting.Property.NodeScope,
Setting.Property.Final
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,18 @@
package org.opensearch.telemetry.diagnostics.jmx;

import com.sun.management.ThreadMXBean;
import org.opensearch.common.SuppressForbidden;

import java.util.function.BiFunction;

/**
* Enum representing different types of JMX metrics and their corresponding value functions.
* Each metric type has a name and a value function that calculates the metric's value
* using the provided {@link ThreadMXBean} and {@link Thread}.
* Enum for all JMX metrics
*/
@SuppressForbidden(reason = "java.lang.management.ThreadMXBean#getThreadAllocatedBytes() not supported")
public enum JMXMetricType {

/**
* CPU time used by a thread.
*/
CPU_TIME("cpu_time", (threadMXBean, t) -> threadMXBean.getThreadCpuTime(t.getId())),

/**
* Number of bytes allocated by a thread.
*/
ALLOCATED_BYTES("allocated_bytes", (threadMXBean, t) -> threadMXBean.getThreadAllocatedBytes(t.getId())),

/**
* Number of times a thread has been blocked.
*/
BLOCKED_COUNT("blocked_count", (threadMXBean, t) -> threadMXBean.getThreadInfo(t.getId()).getBlockedCount()),

/**
* Amount of time a thread has spent blocked.
*/
BLOCKED_TIME("blocked_time", (threadMXBean, t) -> threadMXBean.getThreadInfo(t.getId()).getBlockedTime()),

/**
* Number of times a thread has waited.
*/
WAITED_COUNT("waited_count", (threadMXBean, t) -> threadMXBean.getThreadInfo(t.getId()).getWaitedCount()),

/**
* Amount of time a thread has spent waiting.
*/
WAITED_TIME("waited_time", (threadMXBean, t) -> threadMXBean.getThreadInfo(t.getId()).getWaitedTime());

private final String name;
Expand All @@ -59,23 +31,13 @@ public enum JMXMetricType {
this.valueFunction = valueFunction;
}

/**
* Get the name of the JMX metric type.
*
* @return the name of the metric type
*/
public String getName() {
return name;
}

/**
* Get the value of the JMX metric for the given thread using the provided {@link ThreadMXBean}.
*
* @param threadMXBean the ThreadMXBean used to calculate the metric value
* @param t the Thread for which the metric value is calculated
* @return the calculated value of the metric
*/
public long getValue(ThreadMXBean threadMXBean, Thread t) {
return valueFunction.apply(threadMXBean, t);
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
package org.opensearch.telemetry.diagnostics.jmx;

import com.sun.management.ThreadMXBean;
import org.opensearch.common.SuppressForbidden;
import org.opensearch.telemetry.diagnostics.ThreadResourceObserver;
import org.opensearch.telemetry.metrics.Measurement;
import org.opensearch.telemetry.metrics.MetricPoint;
Expand All @@ -18,34 +17,16 @@
import java.util.HashMap;
import java.util.Map;

/**
* Implementation of {@link ThreadResourceObserver} that observes various JMX metrics for a given thread.
* It collects metrics such as CPU time, allocated bytes, blocked count, blocked time, waited count, and waited time
* for the specified thread using {@link ThreadMXBean}.
*/
@SuppressForbidden(reason = "java.lang.management.ThreadMXBean#getThreadAllocatedBytes() not supported")
public class JMXMetricsObserverThread implements ThreadResourceObserver {
private static final ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();

/**
* Default constructor
*/
public JMXMetricsObserverThread() {

}

/**
* Observes JMX metrics for the given thread and creates a {@link MetricPoint} containing the measured values.
*
* @param t The thread for which to observe metrics.
* @return A {@link MetricPoint} containing the observed JMX metrics for the specified thread.
*/
@Override
public MetricPoint observe(Thread t) {
long measurementTime = System.currentTimeMillis();
Map<String, Measurement<Number>> measurements = new HashMap<>();
for (JMXMetricType measurement : JMXMetricType.values()) {
measurements.put(measurement.getName(), new Measurement<>(measurement.getName(), measurement.getValue(threadMXBean, t)));
measurements.put(measurement.getName(),
new Measurement<>(measurement.getName(), measurement.getValue(threadMXBean, t)));
}
return new MetricPoint(measurements, null, measurementTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,82 +24,44 @@

import static org.opensearch.telemetry.diagnostics.DiagnosticsEventListener.ELAPSED_TIME;

/**
* JMXOTelMetricEmitter is a MetricEmitter implementation that emits metrics using OpenTelemetry.
* It creates histograms for each {@link JMXMetricType} and records the metrics using the provided OpenTelemetry.
* The emitted metrics include the measurements received from the MetricPoint along with their attributes.
*/
public class JMXOTelMetricEmitter implements MetricEmitter {

private static JMXOTelMetricEmitter INSTANCE;
static final Map<String, LongHistogram> histograms = new HashMap<>();

public static Map<String, LongHistogram> histograms = new HashMap<>();
private static Meter meter;

/**
* Private constructor for JMXOTelMetricEmitter.
* It initializes the histograms for each JMX metric type using the provided OpenTelemetry.
*
* @param telemetry the OpenTelemetry instance to use for creating histograms
*/
private JMXOTelMetricEmitter(OpenTelemetry telemetry) {
JMXOTelMetricEmitter.meter = telemetry.getMeter(JMXOTelMetricEmitter.class.getName());

for (JMXMetricType metricType : JMXMetricType.values()) {
LongHistogram histogram = AccessController.doPrivileged(
(PrivilegedAction<LongHistogram>) () -> meter.histogramBuilder(metricType.getName()).ofLongs().build()
);
LongHistogram histogram = AccessController.doPrivileged((PrivilegedAction<LongHistogram>) () ->
meter.histogramBuilder(metricType.getName()).ofLongs().build());
histograms.put(metricType.getName(), histogram);
}

histograms.put(ELAPSED_TIME, meter.histogramBuilder(ELAPSED_TIME).ofLongs().build());
}

/**
* Get the singleton instance of JMXOTelMetricEmitter.
* If the instance does not exist, it creates a new one using the provided OpenTelemetry.
*
* @param telemetry the OpenTelemetry instance to use for creating the singleton instance
* @return the singleton instance of JMXOTelMetricEmitter
*/
synchronized public static JMXOTelMetricEmitter getInstance(OpenTelemetry telemetry) {
if (INSTANCE == null) {
INSTANCE = new JMXOTelMetricEmitter(telemetry);
}
return INSTANCE;
}

/**
* Emit the given MetricPoint using OpenTelemetry.
* The method creates attributes for the metrics from the MetricPoint and records them to the corresponding histograms.
*
* @param metric the MetricPoint to emit
*/
@Override
public void emitMetric(MetricPoint metric) {
AttributesBuilder attributesBuilder = Attributes.builder();
if (metric.getAttributes() != null) {
metric.getAttributes().forEach((k, v) -> attributesBuilder.put(k, String.valueOf(v)));
metric.getAttributes().forEach((k,v) -> attributesBuilder.put(k,String.valueOf(v)));
}
Attributes oTelAttributes = attributesBuilder.build();

for (String measurementName : metric.getMeasurements().keySet()) {
recordToHistogram(metric.getMeasurement(measurementName), oTelAttributes);
}
}

/**
* Records the given measurement to the corresponding histogram using OpenTelemetry.
*
* @param measurement the Measurement to record
* @param oTelAttributes the OpenTelemetry Attributes to associate with the recorded value
*/
private void recordToHistogram(Measurement<Number> measurement, Attributes oTelAttributes) {
LongHistogram histogram = JMXOTelMetricEmitter.histograms.get(measurement.getName());
// assuming all measurements are of long type
long value = measurement.getValue().longValue();
histogram.record(value, oTelAttributes);
// recording 0 value right after as it's the delta which we are emitting and not a gauge
// recording 0 value right after as it's the delta which we are emitting and not gauge
histogram.record(0, oTelAttributes);
}
}
Loading