88import io .opentelemetry .api .common .AttributeKey ;
99import io .opentelemetry .api .common .Attributes ;
1010import io .opentelemetry .api .common .AttributesBuilder ;
11+ import io .opentelemetry .api .common .KeyValue ;
12+ import io .opentelemetry .api .common .Value ;
13+ import io .opentelemetry .api .common .ValueType ;
14+ import java .nio .ByteBuffer ;
1115import java .util .ArrayList ;
1216import java .util .List ;
1317import java .util .Map ;
@@ -60,6 +64,27 @@ private static boolean isValidLength(Object value, int lengthLimit) {
6064 return allMatch ((List <?>) value , entry -> isValidLength (entry , lengthLimit ));
6165 } else if (value instanceof String ) {
6266 return ((String ) value ).length () < lengthLimit ;
67+ } else if (value instanceof Value ) {
68+ return isValidLengthValue ((Value <?>) value , lengthLimit );
69+ }
70+ return true ;
71+ }
72+
73+ private static boolean isValidLengthValue (Value <?> value , int lengthLimit ) {
74+ ValueType type = value .getType ();
75+ if (type == ValueType .STRING ) {
76+ return ((String ) value .getValue ()).length () < lengthLimit ;
77+ } else if (type == ValueType .BYTES ) {
78+ ByteBuffer buffer = (ByteBuffer ) value .getValue ();
79+ return buffer .remaining () <= lengthLimit ;
80+ } else if (type == ValueType .ARRAY ) {
81+ @ SuppressWarnings ("unchecked" )
82+ List <Value <?>> array = (List <Value <?>>) value .getValue ();
83+ return allMatch (array , element -> isValidLengthValue (element , lengthLimit ));
84+ } else if (type == ValueType .KEY_VALUE_LIST ) {
85+ @ SuppressWarnings ("unchecked" )
86+ List <KeyValue > kvList = (List <KeyValue >) value .getValue ();
87+ return allMatch (kvList , kv -> isValidLengthValue (kv .getValue (), lengthLimit ));
6388 }
6489 return true ;
6590 }
@@ -74,8 +99,19 @@ private static <T> boolean allMatch(Iterable<T> iterable, Predicate<T> predicate
7499 }
75100
76101 /**
77- * Apply the {@code lengthLimit} to the attribute {@code value}. Strings and strings in lists
78- * which exceed the length limit are truncated.
102+ * Apply the {@code lengthLimit} to the attribute {@code value}. Strings, byte arrays, and nested
103+ * values which exceed the length limit are truncated.
104+ *
105+ * <p>Applies to:
106+ *
107+ * <ul>
108+ * <li>String values
109+ * <li>Each string within an array of strings
110+ * <li>String values within {@link Value} objects
111+ * <li>Byte array values within {@link Value} objects
112+ * <li>Recursively, each element in an array of {@link Value}s
113+ * <li>Recursively, each value in a {@link Value} key-value list
114+ * </ul>
79115 */
80116 public static Object applyAttributeLengthLimit (Object value , int lengthLimit ) {
81117 if (lengthLimit == Integer .MAX_VALUE ) {
@@ -93,6 +129,48 @@ public static Object applyAttributeLengthLimit(Object value, int lengthLimit) {
93129 String str = (String ) value ;
94130 return str .length () < lengthLimit ? value : str .substring (0 , lengthLimit );
95131 }
132+ if (value instanceof Value ) {
133+ return applyValueLengthLimit ((Value <?>) value , lengthLimit );
134+ }
135+ return value ;
136+ }
137+
138+ @ SuppressWarnings ("unchecked" )
139+ private static Value <?> applyValueLengthLimit (Value <?> value , int lengthLimit ) {
140+ ValueType type = value .getType ();
141+
142+ if (type == ValueType .STRING ) {
143+ String str = (String ) value .getValue ();
144+ if (str .length () <= lengthLimit ) {
145+ return value ;
146+ }
147+ return Value .of (str .substring (0 , lengthLimit ));
148+ } else if (type == ValueType .BYTES ) {
149+ ByteBuffer buffer = (ByteBuffer ) value .getValue ();
150+ int length = buffer .remaining ();
151+ if (length <= lengthLimit ) {
152+ return value ;
153+ }
154+ byte [] truncated = new byte [lengthLimit ];
155+ buffer .get (truncated );
156+ return Value .of (truncated );
157+ } else if (type == ValueType .ARRAY ) {
158+ List <Value <?>> array = (List <Value <?>>) value .getValue ();
159+ List <Value <?>> result = new ArrayList <>(array .size ());
160+ for (Value <?> element : array ) {
161+ result .add (applyValueLengthLimit (element , lengthLimit ));
162+ }
163+ return Value .of (result );
164+ } else if (type == ValueType .KEY_VALUE_LIST ) {
165+ List <KeyValue > kvList = (List <KeyValue >) value .getValue ();
166+ List <KeyValue > result = new ArrayList <>(kvList .size ());
167+ for (KeyValue kv : kvList ) {
168+ result .add (KeyValue .of (kv .getKey (), applyValueLengthLimit (kv .getValue (), lengthLimit )));
169+ }
170+ return Value .of (result .toArray (new KeyValue [0 ]));
171+ }
172+
173+ // For BOOLEAN, LONG, DOUBLE - no truncation needed
96174 return value ;
97175 }
98176}
0 commit comments