Skip to content

Commit

Permalink
Error id adjustments for intake v2 (#217)
Browse files Browse the repository at this point in the history
- add transactionId to TraceContext
- Error.id is required in intake v2
- Error.id is 128 bits long

closes #213
  • Loading branch information
felixbarny authored Sep 20, 2018
1 parent e760b93 commit d8b583f
Show file tree
Hide file tree
Showing 16 changed files with 361 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ public void captureException(long epochTimestampMillis, @Nullable Throwable e, @
error.getTransaction().getTransactionId().copyFrom(transaction.getId());
}
error.asChildOf(active);
} else {
error.getTraceContext().getId().setToRandomValue();
}
reporter.report(error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
*/
public class ErrorCapture implements Recyclable {

private final TraceContext traceContext = new TraceContext();
private final TraceContext traceContext = TraceContext.with128BitId();

/**
* Context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
package co.elastic.apm.impl.sampling;

import co.elastic.apm.impl.transaction.TraceId;
import co.elastic.apm.impl.transaction.Id;

/**
* This is a implementation of {@link Sampler} which always returns the same sampling decision.
Expand All @@ -44,7 +44,7 @@ public static Sampler of(boolean decision) {
}

@Override
public boolean isSampled(TraceId traceId) {
public boolean isSampled(Id traceId) {
return decision;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
*/
package co.elastic.apm.impl.sampling;

import co.elastic.apm.impl.transaction.TraceId;
import co.elastic.apm.impl.transaction.TransactionId;
import co.elastic.apm.impl.transaction.Id;

/**
* This implementation of {@link Sampler} samples based on a sampling probability (or sampling rate) between 0.0 and 1.0.
Expand All @@ -30,9 +29,9 @@
* <p>
* Implementation notes:
* </p>
* We are taking advantage of the fact, that the {@link TransactionId} is randomly generated.
* We are taking advantage of the fact, that the {@link Id} is randomly generated.
* So instead of generating another random number,
* we just see if the long value returned by {@link TransactionId#getMostSignificantBits()}
* we just see if the long value returned by {@link Id#getLeastSignificantBits()}
* falls into the range between the {@code lowerBound} and the <code>higherBound</code>.
* This is a visual representation of the mechanism with a sampling rate of 0.5 (=50%):
* <pre>
Expand All @@ -49,6 +48,11 @@ public class ProbabilitySampler implements Sampler {
private final long lowerBound;
private final long higherBound;

private ProbabilitySampler(double samplingRate) {
higherBound = (long) (Long.MAX_VALUE * samplingRate);
lowerBound = -higherBound;
}

public static Sampler of(double samplingRate) {
if (samplingRate == 1) {
return ConstantSampler.of(true);
Expand All @@ -59,14 +63,9 @@ public static Sampler of(double samplingRate) {
return new ProbabilitySampler(samplingRate);
}

private ProbabilitySampler(double samplingRate) {
higherBound = (long) (Long.MAX_VALUE * samplingRate);
lowerBound = -higherBound;
}

@Override
public boolean isSampled(TraceId traceId) {
final long mostSignificantBits = traceId.getMostSignificantBits();
public boolean isSampled(Id traceId) {
final long mostSignificantBits = traceId.getLeastSignificantBits();
return mostSignificantBits > lowerBound && mostSignificantBits < higherBound;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
package co.elastic.apm.impl.sampling;

import co.elastic.apm.impl.transaction.Span;
import co.elastic.apm.impl.transaction.TraceId;
import co.elastic.apm.impl.transaction.Id;
import co.elastic.apm.impl.transaction.Transaction;

/**
Expand All @@ -45,5 +45,5 @@ public interface Sampler {
* @param traceId The id of the transaction.
* @return The sampling decision.
*/
boolean isSampled(TraceId traceId);
boolean isSampled(Id traceId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

public abstract class AbstractSpan<T extends AbstractSpan> implements Recyclable {
private static final Logger logger = LoggerFactory.getLogger(AbstractSpan.class);
protected final TraceContext traceContext = new TraceContext();
protected final TraceContext traceContext = TraceContext.with64BitId();
/**
* Generic designation of a transaction in the scope of a single service (eg: 'GET /users/:id')
*/
Expand Down
170 changes: 170 additions & 0 deletions apm-agent-core/src/main/java/co/elastic/apm/impl/transaction/Id.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*-
* #%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.impl.transaction;

import co.elastic.apm.objectpool.Recyclable;
import co.elastic.apm.util.HexUtils;
import com.dslplatform.json.JsonWriter;

import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
* A 128 bit globally unique ID of the whole trace forest
*/
public class Id implements Recyclable {

private final byte[] data;
private boolean empty = true;
@Nullable
private String cachedStringRepresentation;

public static Id new128BitId() {
return new Id(16);
}

public static Id new64BitId() {
return new Id(8);
}

private Id(int idLengthBytes) {
data = new byte[idLengthBytes];
}

public void setToRandomValue() {
setToRandomValue(ThreadLocalRandom.current());
}

public void setToRandomValue(Random random) {
random.nextBytes(data);
onMutation(false);
}

public void fromHexString(String hexEncodedString, int offset) {
HexUtils.nextBytes(hexEncodedString, offset, data);
onMutation();
}

public void fromLongs(long... values) {
if (values.length * Long.BYTES != data.length) {
throw new IllegalArgumentException("Invalid number of long values");
}
final ByteBuffer buffer = ByteBuffer.wrap(data);
for (long value : values) {
buffer.putLong(value);
}
onMutation();
}

@Override
public void resetState() {
for (int i = 0; i < data.length; i++) {
data[i] = 0;
}
onMutation(true);
}

public void copyFrom(Id other) {
System.arraycopy(other.data, 0, data, 0, data.length);
onMutation(other.empty);
}

private void onMutation() {
onMutation(isAllZeros(data));
}

private void onMutation(boolean empty) {
cachedStringRepresentation = null;
this.empty = empty;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Id that = (Id) o;
return Arrays.equals(data, that.data);
}

@Override
public int hashCode() {
return Arrays.hashCode(data);
}

@Override
public String toString() {
String s = cachedStringRepresentation;
if (s == null) {
s = cachedStringRepresentation = HexUtils.bytesToHex(data);
}
return s;
}

public boolean isEmpty() {
return empty;
}

private static boolean isAllZeros(byte[] bytes) {
for (byte b : bytes) {
if (b != 0) {
return false;
}
}
return true;
}

public void writeAsHex(JsonWriter jw) {
HexUtils.writeBytesAsHex(data, jw);
}

public void writeAsHex(StringBuilder sb) {
HexUtils.writeBytesAsHex(data, sb);
}

/**
* Returns the last 8 bytes of this id as a {@code long}.
* <p>
* The least significant bits (the right part) of an id is preferred to be used for making random sampling decisions.
* </p>
* <p>
* "There are systems that make random sampling decisions based on the value of trace-id.
* So to increase interoperability it is recommended to keep the random part on the right side of trace-id value."
* </p>
* @see <a href="https://github.com/w3c/distributed-tracing/blob/master/trace_context/HTTP_HEADER_FORMAT.md#trace-id">W3C trace context spec</a>
* @return the last 8 bytes of this id as a {@code long}
*/
public long getLeastSignificantBits() {
return readLong(data.length - 8);
}

/**
* Converts the next 8 bytes, starting from the offset, to a {@code long}
*/
public long readLong(int offset) {
long lsb = 0;
for (int i = offset; i < offset + 8; i++) {
lsb = (lsb << 8) | (data[i] & 0xff);
}
return lsb;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
/**
* A 64 bit random id which is used as a unique id for {@link Span}s within a {@link Transaction}
*/
@Deprecated
public class SpanId implements Recyclable {

private static final int LENGTH = 8;
Expand Down
Loading

0 comments on commit d8b583f

Please sign in to comment.