Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic metrics
Browse files Browse the repository at this point in the history
felixbarny committed Dec 13, 2018
1 parent f2a89b3 commit 49a0efd
Showing 25 changed files with 842 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -36,6 +36,8 @@
import java.util.Set;
import java.util.TreeSet;

import static co.elastic.apm.agent.configuration.validation.RangeValidator.isInRange;

public class CoreConfiguration extends ConfigurationOptionProvider {

public static final String ACTIVE = "active";
@@ -102,16 +104,7 @@ public class CoreConfiguration extends ConfigurationOptionProvider {
"To reduce overhead and storage requirements, you can set the sample rate to a value between 0.0 and 1.0. " +
"We still record overall time and the result for unsampled transactions, but no context information, tags, or spans.")
.dynamic(true)
.addValidator(new ConfigurationOption.Validator<Double>() {
@Override
public void assertValid(Double value) {
if (value != null) {
if (value < 0 || value > 1) {
throw new IllegalArgumentException("The sample rate must be between 0 and 1");
}
}
}
})
.addValidator(isInRange(0d, 1d))
.buildWithDefault(1.0);

private final ConfigurationOption<Integer> transactionMaxSpans = ConfigurationOption.integerOption()
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TimeDuration {
public class TimeDuration implements Comparable<TimeDuration> {

public static final Pattern DURATION_PATTERN = Pattern.compile("^(-)?(\\d+)(ms|s|m)$");
private final String durationString;
@@ -68,4 +68,9 @@ public long getMillis() {
public String toString() {
return durationString;
}

@Override
public int compareTo(TimeDuration o) {
return Long.compare(durationMs, o.durationMs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 Elastic and contributors
* %%
* 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.
* #L%
*/
package co.elastic.apm.agent.configuration.validation;

import org.stagemonitor.configuration.ConfigurationOption;

import javax.annotation.Nullable;

public class RangeValidator<T extends Comparable> implements ConfigurationOption.Validator<T> {

@Nullable
private final T min;
@Nullable
private final T max;
private final boolean mustBeInRange;

private RangeValidator(@Nullable T min, @Nullable T max, boolean mustBeInRange) {
this.min = min;
this.max = max;
this.mustBeInRange = mustBeInRange;
}

public static <T extends Comparable> RangeValidator<T> isInRange(T min, T max) {
return new RangeValidator<>(min, max, true);
}

public static <T extends Comparable> RangeValidator<T> isNotInRange(T min, T max) {
return new RangeValidator<>(min, max, false);
}

public static <T extends Comparable> RangeValidator<T> min(T min) {
return new RangeValidator<>(min, null, true);
}

public static <T extends Comparable> RangeValidator<T> max(T max) {
return new RangeValidator<>(null, max, true);
}

@Override
public void assertValid(@Nullable T value) {
if (value != null) {
boolean isInRange = true;
if (min != null) {
isInRange = min.compareTo(value) <= 0;
}
if (max != null) {
isInRange &= value.compareTo(max) <= 0;
}

if (!isInRange && mustBeInRange) {
throw new IllegalArgumentException(value + " must be in the range [" + min + "," + max + "]");
}

if (isInRange && !mustBeInRange) {
throw new IllegalArgumentException(value + " must not be in the range [" + min + "," + max + "]");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -29,8 +29,9 @@
import co.elastic.apm.agent.impl.transaction.Span;
import co.elastic.apm.agent.impl.transaction.TraceContext;
import co.elastic.apm.agent.impl.transaction.Transaction;
import co.elastic.apm.agent.objectpool.ObjectPool;
import co.elastic.apm.agent.metrics.MetricRegistry;
import co.elastic.apm.agent.objectpool.Allocator;
import co.elastic.apm.agent.objectpool.ObjectPool;
import co.elastic.apm.agent.objectpool.impl.QueueBasedObjectPool;
import co.elastic.apm.agent.report.Reporter;
import co.elastic.apm.agent.report.ReporterConfiguration;
@@ -75,6 +76,7 @@ protected Deque<Object> initialValue() {
};
private final CoreConfiguration coreConfiguration;
private final List<SpanListener> spanListeners;
private final MetricRegistry metricRegistry = new MetricRegistry();
private Sampler sampler;

ElasticApmTracer(ConfigurationRegistry configurationRegistry, Reporter reporter, Iterable<LifecycleListener> lifecycleListeners, List<SpanListener> spanListeners) {
@@ -120,6 +122,7 @@ public void onChange(ConfigurationOption<?> configurationOption, Double oldValue
for (SpanListener spanListener : spanListeners) {
spanListener.init(this);
}
reporter.scheduleMetricReporting(metricRegistry, configurationRegistry.getConfig(ReporterConfiguration.class).getMetricsIntervalMs());
}

public Transaction startTransaction() {
@@ -396,4 +399,8 @@ private void assertIsActive(Object span, @Nullable Object currentlyActive) {
}
assert span == currentlyActive;
}

public MetricRegistry getMetricRegistry() {
return metricRegistry;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 Elastic and contributors
* %%
* 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.
* #L%
*/
package co.elastic.apm.agent.metrics;

public interface DoubleSupplier {

double get();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 Elastic and contributors
* %%
* 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.
* #L%
*/
package co.elastic.apm.agent.metrics;

import com.dslplatform.json.JsonWriter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MetricRegistry {

private static final byte NEW_LINE = '\n';
private final Map<Map<String, String>, MetricSet> metricSets = new ConcurrentHashMap<>();

public void addUnlessNan(String name, Map<String, String> tags, DoubleSupplier metric) {
if (!Double.isNaN(metric.get())) {
add(name, tags, metric);
}
}

public void add(String name, Map<String, String> tags, DoubleSupplier metric) {
MetricSet metricSet = metricSets.get(tags);
if (metricSet == null) {
metricSets.putIfAbsent(tags, new MetricSet(tags));
metricSet = metricSets.get(tags);
}
metricSet.add(name, metric);
}

public void serialize(JsonWriter jw, StringBuilder replaceBuilder) {
final long timestamp = System.currentTimeMillis() * 1000;
for (MetricSet metricSet : metricSets.values()) {
metricSet.serialize(timestamp, replaceBuilder, jw);
jw.writeByte(NEW_LINE);
}
}

public double get(String name, Map<String, String> tags) {
final MetricSet metricSet = metricSets.get(tags);
if (metricSet != null) {
return metricSet.get(name).get();
}
return Double.NaN;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 Elastic and contributors
* %%
* 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.
* #L%
*/
package co.elastic.apm.agent.metrics;

import co.elastic.apm.agent.report.serialize.DslJsonSerializer;
import com.dslplatform.json.JsonWriter;
import com.dslplatform.json.NumberConverter;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MetricSet {
private final Map<String, String> tags;
private final Map<String, DoubleSupplier> samples = new ConcurrentHashMap<>();

MetricSet(Map<String, String> tags) {
this.tags = tags;
}

public void add(String name, DoubleSupplier metric) {
samples.putIfAbsent(name, metric);
}

DoubleSupplier get(String name) {
return samples.get(name);
}

public void serialize(long epochMicros, StringBuilder replaceBuilder, JsonWriter jw) {
jw.writeByte(JsonWriter.OBJECT_START);
{
DslJsonSerializer.writeFieldName("metricset", jw);
jw.writeByte(JsonWriter.OBJECT_START);
{
DslJsonSerializer.writeFieldName("timestamp", jw);
NumberConverter.serialize(epochMicros, jw);
jw.writeByte(JsonWriter.COMMA);

if (!tags.isEmpty()) {
DslJsonSerializer.writeFieldName("tags", jw);
DslJsonSerializer.serializeTags(tags, replaceBuilder, jw);
jw.writeByte(JsonWriter.COMMA);
}

DslJsonSerializer.writeFieldName("samples", jw);
serializeSamples(samples, jw);
}
jw.writeByte(JsonWriter.OBJECT_END);
}
jw.writeByte(JsonWriter.OBJECT_END);
}

private void serializeSamples(Map<String, DoubleSupplier> samples, JsonWriter jw) {
jw.writeByte(JsonWriter.OBJECT_START);
final int size = samples.size();
if (size > 0) {
final Iterator<Map.Entry<String, DoubleSupplier>> iterator = samples.entrySet().iterator();
Map.Entry<String, DoubleSupplier> kv = iterator.next();
serializeSample(kv.getKey(), kv.getValue().get(), jw);
for (int i = 1; i < size; i++) {
jw.writeByte(JsonWriter.COMMA);
kv = iterator.next();
serializeSample(kv.getKey(), kv.getValue().get(), jw);
}
}
jw.writeByte(JsonWriter.OBJECT_END);
}

private void serializeSample(String key, double value, JsonWriter jw) {
jw.writeString(key);
jw.writeByte(JsonWriter.SEMI);
jw.writeByte(JsonWriter.OBJECT_START);
{
DslJsonSerializer.writeFieldName("value", jw);
NumberConverter.serialize(value, jw);
}
jw.writeByte(JsonWriter.OBJECT_END);
}
}
Loading

0 comments on commit 49a0efd

Please sign in to comment.