net.bytebuddy
diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/context/AbstractLifecycleListener.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractLifecycleListener.java
similarity index 83%
rename from apm-agent-core/src/main/java/co/elastic/apm/agent/context/AbstractLifecycleListener.java
rename to apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractLifecycleListener.java
index 02c4f0c0be..6489ae1441 100644
--- a/apm-agent-core/src/main/java/co/elastic/apm/agent/context/AbstractLifecycleListener.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractLifecycleListener.java
@@ -16,17 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-package co.elastic.apm.agent.context;
-
-import co.elastic.apm.agent.impl.ElasticApmTracer;
+package co.elastic.apm.agent.tracer;
public abstract class AbstractLifecycleListener implements LifecycleListener {
@Override
- public void init(ElasticApmTracer tracer) throws Exception {
+ public void init(Tracer tracer) throws Exception {
}
@Override
- public void start(ElasticApmTracer tracer) throws Exception {
+ public void start(Tracer tracer) throws Exception {
}
@Override
diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java
index 9cae3d1b20..692ffdca5e 100644
--- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java
@@ -19,13 +19,17 @@
package co.elastic.apm.agent.tracer;
import co.elastic.apm.agent.tracer.dispatch.HeaderGetter;
+import co.elastic.apm.agent.tracer.metrics.DoubleSupplier;
+import co.elastic.apm.agent.tracer.metrics.Labels;
import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory;
import co.elastic.apm.agent.tracer.reference.ReferenceCounted;
import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap;
import co.elastic.apm.agent.tracer.service.Service;
+import com.dslplatform.json.JsonWriter;
import javax.annotation.Nullable;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
public class GlobalTracer implements Tracer {
@@ -166,4 +170,35 @@ public void flush() {
public void completeMetaData(String name, String version, String id, String region) {
tracer.completeMetaData(name, version, id, region);
}
+
+ @Override
+ public void removeGauge(String name, Labels.Immutable labels) {
+ tracer.removeGauge(name, labels);
+ }
+
+ @Override
+ public void addGauge(String name, Labels.Immutable labels, DoubleSupplier supplier) {
+ tracer.addGauge(name, labels, supplier);
+ }
+
+ @Override
+ public void submit(Runnable job) {
+ tracer.submit(job);
+ }
+
+ @Override
+ public void schedule(Runnable job, long interval, TimeUnit timeUnit) {
+ tracer.schedule(job, interval, timeUnit);
+ }
+
+ @Override
+ public void addShutdownHook(AutoCloseable hook) {
+ tracer.addShutdownHook(hook);
+ }
+
+ @Override
+ public void reportMetric(JsonWriter metrics) {
+ tracer.reportMetric(metrics);
+ }
+
}
diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/context/LifecycleListener.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/LifecycleListener.java
similarity index 74%
rename from apm-agent-core/src/main/java/co/elastic/apm/agent/context/LifecycleListener.java
rename to apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/LifecycleListener.java
index 3b4716518c..a1b55634c4 100644
--- a/apm-agent-core/src/main/java/co/elastic/apm/agent/context/LifecycleListener.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/LifecycleListener.java
@@ -16,42 +16,39 @@
* specific language governing permissions and limitations
* under the License.
*/
-package co.elastic.apm.agent.context;
-
-import co.elastic.apm.agent.impl.ElasticApmTracer;
-import co.elastic.apm.agent.impl.Tracer;
+package co.elastic.apm.agent.tracer;
/**
- * A {@link LifecycleListener} notifies about the start and stop event of the {@link ElasticApmTracer}.
+ * A {@link LifecycleListener} notifies about the start and stop event of the {@link Tracer}.
*
* Implement this interface and register it as a {@linkplain java.util.ServiceLoader service} under
- * {@code src/main/resources/META-INF/services/co.elastic.apm.agent.context.LifecycleListener}.
+ * {@code src/main/resources/META-INF/services/co.elastic.apm.agent.tracer.LifecycleListener}.
*
*
- * Implementations may have a constructor with an {@link ElasticApmTracer} argument
+ * Implementations may have a constructor with an {@link Tracer} argument
*
*/
public interface LifecycleListener {
/**
- * Callback for tracer initialization. As opposed to {@link LifecycleListener#start(ElasticApmTracer)}, which may
+ * Callback for tracer initialization. As opposed to {@link LifecycleListener#start(Tracer)}, which may
* be called in a delay, this callback is called at the bootstrap of the JVM, before anything else start.
* This may be useful for listeners that need to operate very early on, for example such that setup class loading
* requirement to support OSGi systems.
* @param tracer the tracer
* @throws Exception
*/
- void init(ElasticApmTracer tracer) throws Exception;
+ void init(Tracer tracer) throws Exception;
/**
- * Callback for when the {@link ElasticApmTracer} starts.
+ * Callback for when the {@link Tracer} starts.
*
* @param tracer The tracer.
*/
- void start(ElasticApmTracer tracer) throws Exception;
+ void start(Tracer tracer) throws Exception;
/**
- * Callback for when {@link ElasticApmTracer#pause()} has been called.
+ * Callback for when the {@link Tracer} is paused.
*
* Typically, this method is used to reduce overhead on the application to a minimum. This can be done by cleaning
* up resources like object pools, as well as by avoiding tracing-related overhead.
@@ -65,7 +62,7 @@ public interface LifecycleListener {
void pause() throws Exception;
/**
- * Callback for when {@link ElasticApmTracer#resume()} has been called.
+ * Callback for when {@link Tracer} resumes.
*
* Typically, used in order to revert the actions taken by the {@link LifecycleListener#pause()} method, allowing
* the agent to restore all tracing capabilities
@@ -79,7 +76,7 @@ public interface LifecycleListener {
void resume() throws Exception;
/**
- * Callback for when {@link ElasticApmTracer#stop()} has been called.
+ * Callback for when the {@link Tracer} is stopped.
*
* Typically, this method is used to clean up resources like thread pools
* so that there are no class loader leaks when a webapp is redeployed in an application server.
@@ -96,17 +93,14 @@ public interface LifecycleListener {
* The order in which lifecycle listeners are called is non-deterministic.
*
*
- * The {@link ElasticApmTracer#getSharedSingleThreadedPool()} is shut down gracefully,
+ * Any {@link Tracer}-managed thread pool is shut down gracefully,
* waiting a moment for the already scheduled tasks to be completed.
* This means that implementations of this method can schedule a last command to this pool that is executed before shutdown.
- * The {@link Tracer#getState()} will still be {@link Tracer.TracerState#RUNNING} in the tasks scheduled to
- * {@link ElasticApmTracer#getSharedSingleThreadedPool()} within this method.
- *
- *
- * The tracer state is set to {@link co.elastic.apm.agent.impl.Tracer.TracerState#STOPPED}.
+ * The {@link Tracer#isRunning()} will still be {@code true} in the tasks scheduled to
+ * complete within {@link Tracer}-managed threads within this method.
*
*
- * The {@link co.elastic.apm.agent.report.Reporter} is closed.
+ * The tracer state is set to {@link Tracer#isRunning()} being {@code false}.
*
*
*
diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java
index ac1610f99d..85fab5a76a 100644
--- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java
@@ -19,15 +19,18 @@
package co.elastic.apm.agent.tracer;
import co.elastic.apm.agent.tracer.dispatch.HeaderGetter;
+import co.elastic.apm.agent.tracer.metrics.DoubleSupplier;
+import co.elastic.apm.agent.tracer.metrics.Labels;
import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory;
import co.elastic.apm.agent.tracer.reference.ReferenceCounted;
import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap;
import co.elastic.apm.agent.tracer.service.Service;
+import com.dslplatform.json.JsonWriter;
import javax.annotation.Nullable;
-import java.io.IOException;
import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
class NoopTracer implements Tracer {
@@ -140,4 +143,28 @@ public void flush() {
@Override
public void completeMetaData(String name, String version, String id, String region) {
}
+
+ @Override
+ public void addGauge(String name, Labels.Immutable labels, DoubleSupplier supplier) {
+ }
+
+ @Override
+ public void removeGauge(String name, Labels.Immutable labels) {
+ }
+
+ @Override
+ public void submit(Runnable job) {
+ }
+
+ @Override
+ public void schedule(Runnable job, long interval, TimeUnit timeUnit) {
+ }
+
+ @Override
+ public void addShutdownHook(AutoCloseable hook) {
+ }
+
+ @Override
+ public void reportMetric(JsonWriter metrics) {
+ }
}
diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java
index 666ea4fca6..4f1d6efc2e 100644
--- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java
@@ -19,13 +19,17 @@
package co.elastic.apm.agent.tracer;
import co.elastic.apm.agent.tracer.dispatch.HeaderGetter;
+import co.elastic.apm.agent.tracer.metrics.DoubleSupplier;
+import co.elastic.apm.agent.tracer.metrics.Labels;
import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory;
import co.elastic.apm.agent.tracer.reference.ReferenceCounted;
import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap;
import co.elastic.apm.agent.tracer.service.Service;
+import com.dslplatform.json.JsonWriter;
import javax.annotation.Nullable;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
public interface Tracer {
@@ -92,6 +96,18 @@ public interface Tracer {
@Nullable
Throwable redactExceptionIfRequired(@Nullable Throwable original);
+ void removeGauge(String name, Labels.Immutable labels);
+
+ void addGauge(String name, Labels.Immutable labels, DoubleSupplier supplier);
+
+ void submit(Runnable job);
+
+ void schedule(Runnable job, long interval, TimeUnit timeUnit);
+
+ void addShutdownHook(AutoCloseable hook);
+
+ void reportMetric(JsonWriter metrics); // TODO: replace with internalized DSL writer that only accepts data.
+
void flush();
void completeMetaData(String name, String version, String id, String region);
diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/DoubleSupplier.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DoubleSupplier.java
similarity index 94%
rename from apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/DoubleSupplier.java
rename to apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DoubleSupplier.java
index 120a72221d..7f5087b653 100644
--- a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/DoubleSupplier.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DoubleSupplier.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package co.elastic.apm.agent.metrics;
+package co.elastic.apm.agent.tracer.metrics;
public interface DoubleSupplier {
diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DslJsonUtil.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DslJsonUtil.java
new file mode 100644
index 0000000000..256c8def4d
--- /dev/null
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/DslJsonUtil.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. 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 co.elastic.apm.agent.tracer.metrics;
+
+import com.dslplatform.json.JsonWriter;
+
+public class DslJsonUtil {
+
+ public static final int MAX_VALUE_LENGTH = 1024;
+
+ private static final String[] DISALLOWED_IN_PROPERTY_NAME = new String[]{".", "*", "\""};
+
+ public static void writeFieldName(final String fieldName, final JsonWriter jw) {
+ jw.writeByte(JsonWriter.QUOTE);
+ jw.writeAscii(fieldName);
+ jw.writeByte(JsonWriter.QUOTE);
+ jw.writeByte(JsonWriter.SEMI);
+ }
+
+
+ public static CharSequence sanitizePropertyName(String key, StringBuilder replaceBuilder) {
+ for (int i = 0; i < DISALLOWED_IN_PROPERTY_NAME.length; i++) {
+ if (key.contains(DISALLOWED_IN_PROPERTY_NAME[i])) {
+ return replaceAll(key, DISALLOWED_IN_PROPERTY_NAME, "_", replaceBuilder);
+ }
+ }
+ return key;
+ }
+
+ private static CharSequence replaceAll(String s, String[] stringsToReplace, String replacement, StringBuilder replaceBuilder) {
+ // uses a instance variable StringBuilder to avoid allocations
+ replaceBuilder.setLength(0);
+ replaceBuilder.append(s);
+ for (String toReplace : stringsToReplace) {
+ replace(replaceBuilder, toReplace, replacement, 0);
+ }
+ return replaceBuilder;
+ }
+
+ static void replace(StringBuilder replaceBuilder, String toReplace, String replacement, int fromIndex) {
+ for (int i = replaceBuilder.indexOf(toReplace, fromIndex); i != -1; i = replaceBuilder.indexOf(toReplace, fromIndex)) {
+ replaceBuilder.replace(i, i + toReplace.length(), replacement);
+ fromIndex = i;
+ }
+ }
+
+ public static void writeStringValue(CharSequence value, final StringBuilder replaceBuilder, final JsonWriter jw) {
+ if (value.length() > MAX_VALUE_LENGTH) {
+ replaceBuilder.setLength(0);
+ replaceBuilder.append(value, 0, Math.min(value.length(), MAX_VALUE_LENGTH + 1));
+ writeStringBuilderValue(replaceBuilder, jw);
+ } else {
+ jw.writeString(value);
+ }
+ }
+
+ private static void writeStringBuilderValue(StringBuilder value, JsonWriter jw) {
+ if (value.length() > MAX_VALUE_LENGTH) {
+ value.setLength(MAX_VALUE_LENGTH - 1);
+ value.append('…');
+ }
+ jw.writeString(value);
+ }
+}
diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/Labels.java
similarity index 98%
rename from apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java
rename to apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/Labels.java
index c6a2e0475d..a48076bbed 100644
--- a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java
+++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/metrics/Labels.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package co.elastic.apm.agent.metrics;
+package co.elastic.apm.agent.tracer.metrics;
import co.elastic.apm.agent.tracer.pooling.Recyclable;
@@ -31,10 +31,6 @@
* However, there are also top-level labels which are not nested under the {@code labels} object,
* for example {@link #getTransactionName()}, {@link #getTransactionType()}, {@link #getSpanType()} and {@link #getSpanSubType()}.
*
- * Metrics are structured into multiple {@link MetricSet}s.
- * For each distinct combination of {@link Labels}, there is one {@link MetricSet}.
- *
- *
* Labels allow for {@link CharSequence}s as a value,
* thus avoiding allocations for {@code transaction.name.toString()} when tracking breakdown metrics for a transaction.
* Iterations over the labels also don't allocate an Iterator, in contrast to {@code Map.entrySet().iterator()}.
diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java b/apm-agent-tracer/src/test/java/co/elastic/apm/agent/tracer/metrics/LabelsTest.java
similarity index 99%
rename from apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java
rename to apm-agent-tracer/src/test/java/co/elastic/apm/agent/tracer/metrics/LabelsTest.java
index 21e55850c0..ef68d9a229 100644
--- a/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java
+++ b/apm-agent-tracer/src/test/java/co/elastic/apm/agent/tracer/metrics/LabelsTest.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package co.elastic.apm.agent.metrics;
+package co.elastic.apm.agent.tracer.metrics;
import org.junit.jupiter.api.Test;