Implement dropped attribute count in logs (#4697)

* Implement dropped attribute count in logs

* PR feedback

* PR feedback
This commit is contained in:
jack-berg 2022-09-16 10:49:06 -05:00 committed by GitHub
parent 591aff6c15
commit a50ceb3959
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 56 additions and 18 deletions

View File

@ -50,8 +50,7 @@ final class LogMarshaler extends MarshalerWithSize {
MarshalerUtil.toBytes(logData.getSeverityText()),
anyValueMarshaler,
attributeMarshalers,
// TODO (trask) implement droppedAttributesCount in LogRecord
0,
logData.getTotalAttributeCount() - logData.getAttributes().size(),
spanContext.getTraceFlags(),
spanContext.getTraceId().equals(INVALID_TRACE_ID) ? null : spanContext.getTraceId(),
spanContext.getSpanId().equals(INVALID_SPAN_ID) ? null : spanContext.getSpanId());

View File

@ -69,6 +69,7 @@ class LogsRequestMarshalerTest {
SpanContext.create(
TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()))
.setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true))
.setTotalAttributeCount(2)
.setEpoch(12345, TimeUnit.NANOSECONDS)
.build()));
@ -111,6 +112,7 @@ class LogsRequestMarshalerTest {
SpanContext.create(
TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()))
.setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true))
.setTotalAttributeCount(2)
.setEpoch(12345, TimeUnit.NANOSECONDS)
.build()));
@ -124,6 +126,7 @@ class LogsRequestMarshalerTest {
.setKey("key")
.setValue(AnyValue.newBuilder().setBoolValue(true).build())
.build());
assertThat(logRecord.getDroppedAttributesCount()).isEqualTo(1);
assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345);
}
@ -148,6 +151,7 @@ class LogsRequestMarshalerTest {
.isEqualTo(Severity.UNDEFINED_SEVERITY_NUMBER.getSeverityNumber());
assertThat(logRecord.getBody()).isEqualTo(AnyValue.newBuilder().setStringValue("").build());
assertThat(logRecord.getAttributesList()).isEmpty();
assertThat(logRecord.getDroppedAttributesCount()).isZero();
assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345);
}

View File

@ -163,4 +163,17 @@ public class LogDataAssert extends AbstractAssert<LogDataAssert, LogData> {
// implementations.
return actual.getAttributes().asMap().equals(attributes.asMap());
}
/** Asserts the log has the given total attributes. */
public LogDataAssert hasTotalAttributeCount(int totalAttributeCount) {
isNotNull();
if (actual.getTotalAttributeCount() != totalAttributeCount) {
failWithActualExpectedAndMessage(
actual.getTotalAttributeCount(),
totalAttributeCount,
"Expected log to have recorded <%s> total attributes but did not",
totalAttributeCount);
}
return this;
}
}

View File

@ -31,7 +31,8 @@ public abstract class TestLogData implements LogData {
.setSpanContext(SpanContext.getInvalid())
.setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER)
.setBody("")
.setAttributes(Attributes.empty());
.setAttributes(Attributes.empty())
.setTotalAttributeCount(0);
}
TestLogData() {}
@ -86,5 +87,8 @@ public abstract class TestLogData implements LogData {
/** Set the attributes. */
public abstract Builder setAttributes(Attributes attributes);
/** Set the total attribute count. */
public abstract Builder setTotalAttributeCount(int totalAttributeCount);
}
}

View File

@ -55,6 +55,7 @@ public class LogAssertionsTest {
.setSeverityText("info")
.setBody("message")
.setAttributes(ATTRIBUTES)
.setTotalAttributeCount(999)
.build();
@Test
@ -109,7 +110,8 @@ public class LogAssertionsTest {
attributeEntry("colors", "red", "blue"),
attributeEntry("conditions", false, true),
attributeEntry("scores", 0L, 1L),
attributeEntry("coins", 0.01, 0.05, 0.1)));
attributeEntry("coins", 0.01, 0.05, 0.1)))
.hasTotalAttributeCount(999);
}
@Test
@ -179,5 +181,7 @@ public class LogAssertionsTest {
AttributeKey.stringKey("bear"),
value -> assertThat(value).hasSize(2))))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(LOG_DATA).hasTotalAttributeCount(11))
.isInstanceOf(AssertionError.class);
}
}

View File

@ -31,7 +31,8 @@ abstract class SdkLogData implements LogData {
Severity severity,
@Nullable String severityText,
Body body,
Attributes attributes) {
Attributes attributes,
int totalAttributeCount) {
return new AutoValue_SdkLogData(
resource,
instrumentationScopeInfo,
@ -40,6 +41,7 @@ abstract class SdkLogData implements LogData {
severity,
severityText,
body,
attributes);
attributes,
totalAttributeCount);
}
}

View File

@ -115,7 +115,8 @@ class SdkReadWriteLogRecord implements ReadWriteLogRecord {
severity,
severityText,
body,
getImmutableAttributes());
getImmutableAttributes(),
attributes == null ? 0 : attributes.getTotalAddedValues());
}
}
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.logs.data;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.logs.LogLimits;
import io.opentelemetry.sdk.resources.Resource;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@ -44,4 +45,13 @@ public interface LogData {
/** Returns the attributes for this log, or {@link Attributes#empty()} if unset. */
Attributes getAttributes();
/**
* Returns the total number of attributes that were recorded on this log.
*
* <p>This number may be larger than the number of attributes that are attached to this log, if
* the total number recorded was greater than the configured maximum value. See {@link
* LogLimits#getMaxNumberOfAttributes()}.
*/
int getTotalAttributeCount();
}

View File

@ -17,6 +17,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.internal.StringUtils;
@ -104,20 +105,20 @@ class SdkLogEmitterTest {
() -> LogLimits.builder().setMaxNumberOfAttributes(maxNumberOfAttrs).build())
.build();
AttributesBuilder attributesBuilder = Attributes.builder();
LogRecordBuilder builder = logEmitterProvider.get("test").logRecordBuilder();
AttributesBuilder expectedAttributes = Attributes.builder();
for (int i = 0; i < 2 * maxNumberOfAttrs; i++) {
attributesBuilder.put("key" + i, i);
AttributeKey<Long> key = AttributeKey.longKey("key" + i);
builder.setAttribute(key, (long) i);
if (i < maxNumberOfAttrs) {
expectedAttributes.put(key, (long) i);
}
}
builder.emit();
logEmitterProvider
.get("test")
.logRecordBuilder()
.setAllAttributes(attributesBuilder.build())
.emit();
// NOTE: cannot guarantee which attributes are retained, only that there are no more that the
// max
assertThat(seenLog.get().toLogData().getAttributes()).hasSize(maxNumberOfAttrs);
assertThat(seenLog.get().toLogData())
.hasAttributes(expectedAttributes.build())
.hasTotalAttributeCount(maxNumberOfAttrs * 2);
}
@Test