Implement dropped attribute count in logs (#4697)
* Implement dropped attribute count in logs * PR feedback * PR feedback
This commit is contained in:
		
							parent
							
								
									591aff6c15
								
							
						
					
					
						commit
						a50ceb3959
					
				|  | @ -50,8 +50,7 @@ final class LogMarshaler extends MarshalerWithSize { | ||||||
|         MarshalerUtil.toBytes(logData.getSeverityText()), |         MarshalerUtil.toBytes(logData.getSeverityText()), | ||||||
|         anyValueMarshaler, |         anyValueMarshaler, | ||||||
|         attributeMarshalers, |         attributeMarshalers, | ||||||
|         // TODO (trask) implement droppedAttributesCount in LogRecord |         logData.getTotalAttributeCount() - logData.getAttributes().size(), | ||||||
|         0, |  | ||||||
|         spanContext.getTraceFlags(), |         spanContext.getTraceFlags(), | ||||||
|         spanContext.getTraceId().equals(INVALID_TRACE_ID) ? null : spanContext.getTraceId(), |         spanContext.getTraceId().equals(INVALID_TRACE_ID) ? null : spanContext.getTraceId(), | ||||||
|         spanContext.getSpanId().equals(INVALID_SPAN_ID) ? null : spanContext.getSpanId()); |         spanContext.getSpanId().equals(INVALID_SPAN_ID) ? null : spanContext.getSpanId()); | ||||||
|  |  | ||||||
|  | @ -69,6 +69,7 @@ class LogsRequestMarshalerTest { | ||||||
|                         SpanContext.create( |                         SpanContext.create( | ||||||
|                             TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault())) |                             TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault())) | ||||||
|                     .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) |                     .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) | ||||||
|  |                     .setTotalAttributeCount(2) | ||||||
|                     .setEpoch(12345, TimeUnit.NANOSECONDS) |                     .setEpoch(12345, TimeUnit.NANOSECONDS) | ||||||
|                     .build())); |                     .build())); | ||||||
| 
 | 
 | ||||||
|  | @ -111,6 +112,7 @@ class LogsRequestMarshalerTest { | ||||||
|                         SpanContext.create( |                         SpanContext.create( | ||||||
|                             TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault())) |                             TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault())) | ||||||
|                     .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) |                     .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) | ||||||
|  |                     .setTotalAttributeCount(2) | ||||||
|                     .setEpoch(12345, TimeUnit.NANOSECONDS) |                     .setEpoch(12345, TimeUnit.NANOSECONDS) | ||||||
|                     .build())); |                     .build())); | ||||||
| 
 | 
 | ||||||
|  | @ -124,6 +126,7 @@ class LogsRequestMarshalerTest { | ||||||
|                 .setKey("key") |                 .setKey("key") | ||||||
|                 .setValue(AnyValue.newBuilder().setBoolValue(true).build()) |                 .setValue(AnyValue.newBuilder().setBoolValue(true).build()) | ||||||
|                 .build()); |                 .build()); | ||||||
|  |     assertThat(logRecord.getDroppedAttributesCount()).isEqualTo(1); | ||||||
|     assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345); |     assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -148,6 +151,7 @@ class LogsRequestMarshalerTest { | ||||||
|         .isEqualTo(Severity.UNDEFINED_SEVERITY_NUMBER.getSeverityNumber()); |         .isEqualTo(Severity.UNDEFINED_SEVERITY_NUMBER.getSeverityNumber()); | ||||||
|     assertThat(logRecord.getBody()).isEqualTo(AnyValue.newBuilder().setStringValue("").build()); |     assertThat(logRecord.getBody()).isEqualTo(AnyValue.newBuilder().setStringValue("").build()); | ||||||
|     assertThat(logRecord.getAttributesList()).isEmpty(); |     assertThat(logRecord.getAttributesList()).isEmpty(); | ||||||
|  |     assertThat(logRecord.getDroppedAttributesCount()).isZero(); | ||||||
|     assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345); |     assertThat(logRecord.getTimeUnixNano()).isEqualTo(12345); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -163,4 +163,17 @@ public class LogDataAssert extends AbstractAssert<LogDataAssert, LogData> { | ||||||
|     // implementations. |     // implementations. | ||||||
|     return actual.getAttributes().asMap().equals(attributes.asMap()); |     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; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -31,7 +31,8 @@ public abstract class TestLogData implements LogData { | ||||||
|         .setSpanContext(SpanContext.getInvalid()) |         .setSpanContext(SpanContext.getInvalid()) | ||||||
|         .setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER) |         .setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER) | ||||||
|         .setBody("") |         .setBody("") | ||||||
|         .setAttributes(Attributes.empty()); |         .setAttributes(Attributes.empty()) | ||||||
|  |         .setTotalAttributeCount(0); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   TestLogData() {} |   TestLogData() {} | ||||||
|  | @ -86,5 +87,8 @@ public abstract class TestLogData implements LogData { | ||||||
| 
 | 
 | ||||||
|     /** Set the attributes. */ |     /** Set the attributes. */ | ||||||
|     public abstract Builder setAttributes(Attributes attributes); |     public abstract Builder setAttributes(Attributes attributes); | ||||||
|  | 
 | ||||||
|  |     /** Set the total attribute count. */ | ||||||
|  |     public abstract Builder setTotalAttributeCount(int totalAttributeCount); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -55,6 +55,7 @@ public class LogAssertionsTest { | ||||||
|           .setSeverityText("info") |           .setSeverityText("info") | ||||||
|           .setBody("message") |           .setBody("message") | ||||||
|           .setAttributes(ATTRIBUTES) |           .setAttributes(ATTRIBUTES) | ||||||
|  |           .setTotalAttributeCount(999) | ||||||
|           .build(); |           .build(); | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | @ -109,7 +110,8 @@ public class LogAssertionsTest { | ||||||
|                         attributeEntry("colors", "red", "blue"), |                         attributeEntry("colors", "red", "blue"), | ||||||
|                         attributeEntry("conditions", false, true), |                         attributeEntry("conditions", false, true), | ||||||
|                         attributeEntry("scores", 0L, 1L), |                         attributeEntry("scores", 0L, 1L), | ||||||
|                         attributeEntry("coins", 0.01, 0.05, 0.1))); |                         attributeEntry("coins", 0.01, 0.05, 0.1))) | ||||||
|  |         .hasTotalAttributeCount(999); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | @ -179,5 +181,7 @@ public class LogAssertionsTest { | ||||||
|                                     AttributeKey.stringKey("bear"), |                                     AttributeKey.stringKey("bear"), | ||||||
|                                     value -> assertThat(value).hasSize(2)))) |                                     value -> assertThat(value).hasSize(2)))) | ||||||
|         .isInstanceOf(AssertionError.class); |         .isInstanceOf(AssertionError.class); | ||||||
|  |     assertThatThrownBy(() -> assertThat(LOG_DATA).hasTotalAttributeCount(11)) | ||||||
|  |         .isInstanceOf(AssertionError.class); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -31,7 +31,8 @@ abstract class SdkLogData implements LogData { | ||||||
|       Severity severity, |       Severity severity, | ||||||
|       @Nullable String severityText, |       @Nullable String severityText, | ||||||
|       Body body, |       Body body, | ||||||
|       Attributes attributes) { |       Attributes attributes, | ||||||
|  |       int totalAttributeCount) { | ||||||
|     return new AutoValue_SdkLogData( |     return new AutoValue_SdkLogData( | ||||||
|         resource, |         resource, | ||||||
|         instrumentationScopeInfo, |         instrumentationScopeInfo, | ||||||
|  | @ -40,6 +41,7 @@ abstract class SdkLogData implements LogData { | ||||||
|         severity, |         severity, | ||||||
|         severityText, |         severityText, | ||||||
|         body, |         body, | ||||||
|         attributes); |         attributes, | ||||||
|  |         totalAttributeCount); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -115,7 +115,8 @@ class SdkReadWriteLogRecord implements ReadWriteLogRecord { | ||||||
|           severity, |           severity, | ||||||
|           severityText, |           severityText, | ||||||
|           body, |           body, | ||||||
|           getImmutableAttributes()); |           getImmutableAttributes(), | ||||||
|  |           attributes == null ? 0 : attributes.getTotalAddedValues()); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ package io.opentelemetry.sdk.logs.data; | ||||||
| import io.opentelemetry.api.common.Attributes; | import io.opentelemetry.api.common.Attributes; | ||||||
| import io.opentelemetry.api.trace.SpanContext; | import io.opentelemetry.api.trace.SpanContext; | ||||||
| import io.opentelemetry.sdk.common.InstrumentationScopeInfo; | import io.opentelemetry.sdk.common.InstrumentationScopeInfo; | ||||||
|  | import io.opentelemetry.sdk.logs.LogLimits; | ||||||
| import io.opentelemetry.sdk.resources.Resource; | import io.opentelemetry.sdk.resources.Resource; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import javax.annotation.concurrent.Immutable; | import javax.annotation.concurrent.Immutable; | ||||||
|  | @ -44,4 +45,13 @@ public interface LogData { | ||||||
| 
 | 
 | ||||||
|   /** Returns the attributes for this log, or {@link Attributes#empty()} if unset. */ |   /** Returns the attributes for this log, or {@link Attributes#empty()} if unset. */ | ||||||
|   Attributes getAttributes(); |   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(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ import static org.mockito.Mockito.never; | ||||||
| import static org.mockito.Mockito.verify; | import static org.mockito.Mockito.verify; | ||||||
| import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||||
| 
 | 
 | ||||||
|  | import io.opentelemetry.api.common.AttributeKey; | ||||||
| import io.opentelemetry.api.common.Attributes; | import io.opentelemetry.api.common.Attributes; | ||||||
| import io.opentelemetry.api.common.AttributesBuilder; | import io.opentelemetry.api.common.AttributesBuilder; | ||||||
| import io.opentelemetry.api.internal.StringUtils; | import io.opentelemetry.api.internal.StringUtils; | ||||||
|  | @ -104,20 +105,20 @@ class SdkLogEmitterTest { | ||||||
|                 () -> LogLimits.builder().setMaxNumberOfAttributes(maxNumberOfAttrs).build()) |                 () -> LogLimits.builder().setMaxNumberOfAttributes(maxNumberOfAttrs).build()) | ||||||
|             .build(); |             .build(); | ||||||
| 
 | 
 | ||||||
|     AttributesBuilder attributesBuilder = Attributes.builder(); |     LogRecordBuilder builder = logEmitterProvider.get("test").logRecordBuilder(); | ||||||
|  |     AttributesBuilder expectedAttributes = Attributes.builder(); | ||||||
|     for (int i = 0; i < 2 * maxNumberOfAttrs; i++) { |     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 |     assertThat(seenLog.get().toLogData()) | ||||||
|         .get("test") |         .hasAttributes(expectedAttributes.build()) | ||||||
|         .logRecordBuilder() |         .hasTotalAttributeCount(maxNumberOfAttrs * 2); | ||||||
|         .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); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue