Skip to content

Commit 0a36759

Browse files
authored
Merge pull request #1189 from microsoft/littleaj/field_truncation
Add field truncation to
2 parents 9b580f9 + 124e3de commit 0a36759

File tree

7 files changed

+237
-8
lines changed

7 files changed

+237
-8
lines changed

core/src/main/java/com/microsoft/applicationinsights/extensibility/context/ContextTagKeys.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ public class ContextTagKeys
128128
// 44: Optional string OperationRootId
129129
private String OperationRootId;
130130

131+
private String OperationCorrelationVector;
132+
131133
// 51: Optional string SessionId
132134
private String SessionId;
133135

@@ -811,6 +813,14 @@ public final String getCloudRoleInstance() {
811813
return this.CloudRoleInstance;
812814
}
813815

816+
public final String getOperationCorrelationVector() {
817+
return OperationCorrelationVector;
818+
}
819+
820+
public final void setOperationCorrelationVector(String operationCorrelationVector) {
821+
OperationCorrelationVector = operationCorrelationVector;
822+
}
823+
814824
public static ContextTagKeys getKeys()
815825
{
816826
return s_keys;
@@ -865,6 +875,7 @@ protected void reset(String name, String qualifiedName) {
865875
OperationId = "ai.operation.id";
866876
OperationParentId = "ai.operation.parentId";
867877
OperationRootId = "ai.operation.rootId";
878+
OperationCorrelationVector = "ai.operation.correlationVector";
868879
SessionId = "ai.session.id";
869880
SessionIsFirst = "ai.session.isFirst";
870881
SessionIsNew = "ai.session.isNew";

core/src/main/java/com/microsoft/applicationinsights/internal/util/MapUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static <Key, Value> Value getValueOrNull(Map<Key, Value> map, Key key) {
7373
}
7474

7575
public static Boolean getBoolValueOrNull(Map<String, String> map, String key) {
76-
return map.containsKey(key) ? Boolean.parseBoolean(map.get(key)) : null;
76+
return map.containsKey(key) ? Boolean.valueOf(map.get(key)) : null;
7777
}
7878

7979
public static Date getDateValueOrNull(Map<String, String> map, String key) {

core/src/main/java/com/microsoft/applicationinsights/telemetry/BaseTelemetry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ protected BaseTelemetry() {
5555
* @param properties The context properties
5656
*/
5757
protected void initialize(ConcurrentMap<String, String> properties) {
58-
this.context = new TelemetryContext(properties, new ConcurrentHashMap<String, String>());
58+
this.context = new TelemetryContext(properties, new ContextTagsMap());
5959
}
6060

6161
public abstract int getVer();
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.microsoft.applicationinsights.telemetry;
2+
3+
import java.util.Collection;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
import java.util.Set;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
import java.util.concurrent.ConcurrentMap;
9+
10+
import com.microsoft.applicationinsights.extensibility.context.ContextTagKeys;
11+
import org.apache.commons.lang3.StringUtils;
12+
13+
/**
14+
* This ensures the values for certain tags do not exceed their limits.
15+
*/
16+
class ContextTagsMap implements ConcurrentMap<String, String> {
17+
18+
private static final Map<String, Integer> tagSizeLimits = new HashMap<>();
19+
20+
21+
static {
22+
tagSizeLimits.put(ContextTagKeys.getKeys().getApplicationVersion(), 1024);
23+
tagSizeLimits.put(ContextTagKeys.getKeys().getDeviceId(), 1024);
24+
tagSizeLimits.put(ContextTagKeys.getKeys().getDeviceModel(), 256);
25+
tagSizeLimits.put(ContextTagKeys.getKeys().getDeviceOEMName(), 256);
26+
tagSizeLimits.put(ContextTagKeys.getKeys().getDeviceOSVersion(), 256);
27+
tagSizeLimits.put(ContextTagKeys.getKeys().getDeviceType(), 64);
28+
tagSizeLimits.put(ContextTagKeys.getKeys().getLocationIP(), 45);
29+
tagSizeLimits.put(ContextTagKeys.getKeys().getOperationId(), 128);
30+
tagSizeLimits.put(ContextTagKeys.getKeys().getOperationName(), 1024);
31+
tagSizeLimits.put(ContextTagKeys.getKeys().getOperationParentId(), 128);
32+
tagSizeLimits.put(ContextTagKeys.getKeys().getSyntheticSource(), 1024);
33+
tagSizeLimits.put(ContextTagKeys.getKeys().getSessionId(), 64);
34+
tagSizeLimits.put(ContextTagKeys.getKeys().getUserId(), 128);
35+
tagSizeLimits.put(ContextTagKeys.getKeys().getUserAccountId(), 1024);
36+
tagSizeLimits.put(ContextTagKeys.getKeys().getUserAuthUserId(), 1024);
37+
tagSizeLimits.put(ContextTagKeys.getKeys().getCloudRole(), 256);
38+
tagSizeLimits.put(ContextTagKeys.getKeys().getCloudRoleInstance(), 256);
39+
tagSizeLimits.put(ContextTagKeys.getKeys().getInternalSdkVersion(), 64);
40+
tagSizeLimits.put(ContextTagKeys.getKeys().getInternalAgentVersion(), 64);
41+
tagSizeLimits.put(ContextTagKeys.getKeys().getInternalNodeName(), 256);
42+
tagSizeLimits.put(ContextTagKeys.getKeys().getOperationCorrelationVector(), 64);
43+
}
44+
45+
private final ConcurrentMap<String, String> tags = new ConcurrentHashMap<>();
46+
47+
private static String sanitizeKey(String key) {
48+
return key;
49+
}
50+
51+
private static String truncate(String value, int maxLength) {
52+
if (value != null && value.length() > maxLength) {
53+
value = StringUtils.truncate(value, maxLength);
54+
}
55+
return value;
56+
}
57+
58+
private String sanitizeValue(String key, String value) {
59+
value = StringUtils.trim(value);
60+
if (tagSizeLimits.containsKey(key)) {
61+
value = truncate(value, tagSizeLimits.get(key));
62+
}
63+
return value;
64+
}
65+
66+
@Override
67+
public String putIfAbsent(String key, String value) {
68+
return tags.putIfAbsent(key, sanitizeValue(key, value));
69+
}
70+
71+
@Override
72+
public boolean remove(Object key, Object value) {
73+
return tags.remove(key, value);
74+
}
75+
76+
@Override
77+
public boolean replace(String key, String oldValue, String newValue) {
78+
return tags.replace(key, oldValue, sanitizeValue(key, newValue));
79+
}
80+
81+
@Override
82+
public String replace(String key, String value) {
83+
return tags.replace(key, sanitizeValue(key, value));
84+
}
85+
86+
@Override
87+
public int size() {
88+
return tags.size();
89+
}
90+
91+
@Override
92+
public boolean isEmpty() {
93+
return tags.isEmpty();
94+
}
95+
96+
@Override
97+
public boolean containsKey(Object key) {
98+
return tags.containsKey(key);
99+
}
100+
101+
@Override
102+
public boolean containsValue(Object value) {
103+
return tags.containsValue(value);
104+
}
105+
106+
@Override
107+
public String get(Object key) {
108+
return tags.get(key);
109+
}
110+
111+
@Override
112+
public String put(String key, String value) {
113+
return tags.put(key, sanitizeValue(key, value));
114+
}
115+
116+
@Override
117+
public String remove(Object key) {
118+
return tags.remove(key);
119+
}
120+
121+
@Override
122+
public void putAll(Map<? extends String, ? extends String> m) {
123+
Map<String, String> sanitized = new HashMap<>();
124+
for (Entry<? extends String, ? extends String> entry : m.entrySet()) {
125+
sanitized.put(entry.getKey(), sanitizeValue(entry.getKey(), entry.getValue()));
126+
}
127+
tags.putAll(sanitized);
128+
}
129+
130+
@Override
131+
public void clear() {
132+
tags.clear();
133+
}
134+
135+
@Override
136+
public Set<String> keySet() {
137+
return tags.keySet();
138+
}
139+
140+
@Override
141+
public Collection<String> values() {
142+
return tags.values();
143+
}
144+
145+
@Override
146+
public Set<Entry<String, String>> entrySet() {
147+
return tags.entrySet();
148+
}
149+
150+
@Override
151+
public boolean equals(Object o) {
152+
return tags.equals(o);
153+
}
154+
155+
@Override
156+
public int hashCode() {
157+
return tags.hashCode();
158+
}
159+
}

core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*/
4646
public final class TelemetryContext {
4747
private ConcurrentMap<String,String> properties;
48-
private ConcurrentMap<String,String> tags;
48+
private ContextTagsMap tags;
4949

5050
private String instrumentationKey;
5151
private ComponentContext component;
@@ -61,7 +61,7 @@ public final class TelemetryContext {
6161
* Default Ctor
6262
*/
6363
public TelemetryContext() {
64-
this(new ConcurrentHashMap<String, String>(), new ConcurrentHashMap<String, String>());
64+
this(new ConcurrentHashMap<String, String>(), new ContextTagsMap());
6565
}
6666

6767
/**
@@ -212,7 +212,7 @@ public InternalContext getInternal() {
212212
return internal;
213213
}
214214

215-
TelemetryContext(ConcurrentMap<String, String> properties, ConcurrentMap<String, String> tags) {
215+
TelemetryContext(ConcurrentMap<String, String> properties, ContextTagsMap tags) {
216216
if (properties == null) {
217217
throw new IllegalArgumentException("properties cannot be null");
218218
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.microsoft.applicationinsights.telemetry;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import com.microsoft.applicationinsights.extensibility.context.ContextTagKeys;
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.junit.*;
9+
10+
import static org.junit.Assert.*;
11+
12+
public class ContextTagsMapTests {
13+
private ContextTagsMap map;
14+
15+
@Before
16+
public void setup() {
17+
map = new ContextTagsMap();
18+
}
19+
20+
@After
21+
public void tearDown() {
22+
map = null;
23+
}
24+
25+
26+
@Test
27+
public void putTruncatesValueOverLimit() {
28+
// max len is 64
29+
String sessionIdKey = ContextTagKeys.getKeys().getSessionId();
30+
String value = StringUtils.repeat("1234", 32);
31+
map.put(sessionIdKey, value);
32+
assertEquals(StringUtils.repeat("1234", 16), map.get(sessionIdKey));
33+
}
34+
35+
@Test
36+
public void putAllTruncatesValuesOverLimit() {
37+
final String locationIpValue = StringUtils.repeat('x', 55); // max=45
38+
final String deviceIdValue = StringUtils.repeat('y', 2048); //max=1024
39+
final String operationParentIdValue = StringUtils.repeat('z', 127); //max=128, this one is intentionally within the limits
40+
41+
final String customKey = "not a limited key";
42+
final String customValue = StringUtils.repeat("1234", 1024);
43+
44+
Map<String, String> kvps = new HashMap<>();
45+
kvps.put(ContextTagKeys.getKeys().getLocationIP(), locationIpValue);
46+
kvps.put(ContextTagKeys.getKeys().getDeviceId(), deviceIdValue);
47+
kvps.put(ContextTagKeys.getKeys().getOperationParentId(), operationParentIdValue);
48+
kvps.put(customKey, customValue);
49+
50+
map.putAll(kvps);
51+
52+
assertEquals(StringUtils.repeat('x', 45), map.get(ContextTagKeys.getKeys().getLocationIP()));
53+
assertEquals(StringUtils.repeat('y', 1024), map.get(ContextTagKeys.getKeys().getDeviceId()));
54+
assertEquals(operationParentIdValue, map.get(ContextTagKeys.getKeys().getOperationParentId()));
55+
assertEquals(customValue, map.get(customKey));
56+
}
57+
58+
}

web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/TelemetryCorrelationUtilsTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package com.microsoft.applicationinsights.web.internal.correlation;
2323

2424
import com.microsoft.applicationinsights.TelemetryConfiguration;
25+
import org.apache.commons.lang3.StringUtils;
2526
import org.junit.*;
2627
import com.microsoft.applicationinsights.extensibility.context.OperationContext;
2728
import com.microsoft.applicationinsights.internal.util.DateTimeUtils;
@@ -405,7 +406,7 @@ public void testRequestIdOverflow() {
405406
//validate operation context ID's
406407
OperationContext operation = requestTelemetry.getContext().getOperation();
407408
assertEquals(rootId, operation.getId());
408-
assertEquals(incomingId, operation.getParentId());
409+
assertEquals(StringUtils.truncate(incomingId, 128), operation.getParentId());
409410
}
410411

411412
@Test
@@ -446,8 +447,8 @@ public void testRequestIdOverflowWithInvalidRequestId() {
446447

447448
//validate operation context ID's
448449
OperationContext operation = requestTelemetry.getContext().getOperation();
449-
assertEquals(incomingId, operation.getId());
450-
assertEquals(incomingId, operation.getParentId());
450+
assertEquals(StringUtils.truncate(incomingId, 128), operation.getId());
451+
assertEquals(StringUtils.truncate(incomingId, 128), operation.getParentId());
451452
}
452453

453454
@Test

0 commit comments

Comments
 (0)