Skip to content

Commit 1318917

Browse files
authored
added regex support and improved retrying (#192)
1 parent b1bf975 commit 1318917

File tree

7 files changed

+57
-67
lines changed

7 files changed

+57
-67
lines changed

validator/src/main/java/com/amazon/aoc/exception/ExceptionCode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public enum ExceptionCode {
2525

2626
// validating errors
2727
TRACE_ID_NOT_MATCHED(50001, "trace id not matched"),
28-
DATA_MODEL_NOT_MATCHED(50006, "trace id not matched"),
28+
DATA_MODEL_NOT_MATCHED(50006, "data model not matched"),
2929
TRACE_SPAN_LIST_NOT_MATCHED(50002, "trace span list has different length"),
3030
TRACE_SPAN_NOT_MATCHED(50003, "trace span not matched"),
3131
TRACE_LIST_NOT_MATCHED(50004, "trace list has different length"),

validator/src/main/java/com/amazon/aoc/helpers/RetryHelper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public static boolean retry(
3737
int retryCount, int sleepInMilliSeconds, boolean throwExceptionInTheEnd, Retryable retryable)
3838
throws Exception {
3939
Exception exceptionInTheEnd = null;
40+
int initialCount = retryCount;
4041
while (retryCount-- > 0) {
4142
try {
4243
log.info("retry attempt left : {} ", retryCount);
@@ -49,8 +50,8 @@ public static boolean retry(
4950
}
5051
}
5152

53+
log.error("All {} retries exhausted", initialCount);
5254
if (throwExceptionInTheEnd) {
53-
log.error("retries exhausted, possible");
5455
throw exceptionInTheEnd;
5556
}
5657
return false;

validator/src/main/java/com/amazon/aoc/models/xray/Entity.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
@Getter
1717
@Setter
18+
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
1819
public class Entity {
1920
private String name;
2021
private String id;
@@ -25,21 +26,13 @@ public class Entity {
2526
private String origin;
2627
private String traceId;
2728

28-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
2929
private double endTime;
30-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
3130
private boolean fault;
32-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
3331
private boolean error;
34-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
3532
private boolean throttle;
36-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
3733
private boolean inProgress;
38-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
3934
private boolean inferred;
40-
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
4135
private boolean stubbed;
42-
4336
private String namespace;
4437

4538
private List<Entity> subsegments;
@@ -48,6 +41,7 @@ public class Entity {
4841
private Map<String, Object> http;
4942
private Map<String, Object> aws;
5043
private Map<String, Object> sql;
44+
private Map<String, Object> service;
5145

5246
private Map<String, Map<String, Object>> metadata;
5347
private Map<String, Object> annotations;

validator/src/main/java/com/amazon/aoc/validators/TraceValidator.java

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.List;
4242
import java.util.Map;
4343
import java.util.concurrent.atomic.AtomicReference;
44+
import java.util.regex.Pattern;
4445

4546
@Log4j2
4647
public class TraceValidator implements IValidator {
@@ -65,39 +66,47 @@ public void init(
6566

6667
@Override
6768
public void validate() throws Exception {
68-
// get stored trace
69-
Map<String, Object> storedTrace = this.getStoredTrace();
70-
log.info("value of stored trace map: {}", storedTrace);
71-
// create trace id list to retrieve trace from x-ray service
72-
String traceId = (String) storedTrace.get("[0].trace_id");
73-
List<String> traceIdList = Collections.singletonList(traceId);
74-
75-
// get retrieved trace from x-ray service
76-
boolean isMatched = RetryHelper.retry(10,
69+
// 2 retries for calling the sample app to handle the Lambda case,
70+
// where first request might be a cold start and have an additional unexpected subsegment
71+
boolean isMatched = RetryHelper.retry(2,
7772
Integer.parseInt(GenericConstants.SLEEP_IN_MILLISECONDS.getVal()),
7873
false,
7974
() -> {
80-
Map<String, Object> retrievedTrace = this.getRetrievedTrace(traceIdList);
81-
log.info("value of retrieved trace map: {}", retrievedTrace);
82-
// data model validation of other fields of segment document
83-
for (Map.Entry<String, Object> entry : storedTrace.entrySet()) {
84-
String targetKey = entry.getKey();
85-
if (retrievedTrace.get(targetKey) == null) {
86-
log.error("mis target data: {}", targetKey);
87-
throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED);
88-
}
89-
if (!entry
90-
.getValue()
91-
.toString()
92-
.equalsIgnoreCase(retrievedTrace.get(targetKey).toString())) {
93-
log.error("data model validation failed");
94-
log.info("mis matched data model field list");
95-
log.info("value of stored trace map: {}", entry.getValue());
96-
log.info("value of retrieved map: {}", retrievedTrace.get(entry.getKey()));
97-
log.info("==========================================");
98-
throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED);
99-
}
100-
}
75+
// Call sample app and get locally stored trace
76+
Map<String, Object> storedTrace = this.getStoredTrace();
77+
log.info("value of stored trace map: {}", storedTrace);
78+
79+
// prepare list of trace IDs to retrieve from X-Ray service
80+
String traceId = (String) storedTrace.get("[0].trace_id");
81+
List<String> traceIdList = Collections.singletonList(traceId);
82+
83+
// Retry 5 times to since segments might not be immediately available in X-Ray service
84+
RetryHelper.retry(
85+
5,
86+
() -> {
87+
// get retrieved trace from x-ray service
88+
Map<String, Object> retrievedTrace = this.getRetrievedTrace(traceIdList);
89+
log.info("value of retrieved trace map: {}", retrievedTrace);
90+
91+
// data model validation of other fields of segment document
92+
for (Map.Entry<String, Object> entry : storedTrace.entrySet()) {
93+
String targetKey = entry.getKey();
94+
if (retrievedTrace.get(targetKey) == null) {
95+
log.error("mis target data: {}", targetKey);
96+
throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED);
97+
}
98+
99+
if (!Pattern.matches(entry.getValue().toString(),
100+
retrievedTrace.get(targetKey).toString())) {
101+
log.error("data model validation failed");
102+
log.info("mis matched data model field list");
103+
log.info("value of stored trace map: {}", entry.getValue());
104+
log.info("value of retrieved map: {}", retrievedTrace.get(entry.getKey()));
105+
log.info("==========================================");
106+
throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED);
107+
}
108+
}
109+
});
101110
});
102111

103112
if (!isMatched) {
@@ -109,28 +118,12 @@ public void validate() throws Exception {
109118

110119
// this method will hit get trace from x-ray service and get retrieved trace
111120
private Map<String, Object> getRetrievedTrace(List<String> traceIdList) throws Exception {
112-
AtomicReference<Map<String, Object>> flattenedJsonMapForRetrievedTrace =
113-
new AtomicReference<>();
114-
RetryHelper.retry(
115-
30,
116-
() -> {
117-
List<Trace> retrieveTraceList = null;
118-
retrieveTraceList = xrayService.listTraceByIds(traceIdList);
119-
if (retrieveTraceList == null || retrieveTraceList.isEmpty()) {
120-
throw new BaseException(ExceptionCode.EMPTY_LIST);
121-
}
122-
123-
// in case the json format is wrong, retry it.
124-
if (!retrieveTraceList.isEmpty()) {
125-
flattenedJsonMapForRetrievedTrace.set(
126-
this.flattenDocument(retrieveTraceList.get(0).getSegments()));
127-
} else {
128-
log.error("retrieved trace list is empty or null");
129-
throw new BaseException(ExceptionCode.EMPTY_LIST);
130-
}
131-
});
132-
133-
return flattenedJsonMapForRetrievedTrace.get();
121+
List<Trace> retrieveTraceList = xrayService.listTraceByIds(traceIdList);
122+
if (retrieveTraceList == null || retrieveTraceList.isEmpty()) {
123+
throw new BaseException(ExceptionCode.EMPTY_LIST);
124+
}
125+
126+
return this.flattenDocument(retrieveTraceList.get(0).getSegments());
134127
}
135128

136129
private Map<String, Object> flattenDocument(List<Segment> segmentList) {

validator/src/main/resources/expected-data-template/lambdaExpectedTrace.mustache

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
]
99
},
1010
{
11+
"name":"serverlessrepo-aot-py38-sar-function-.*",
1112
"http":{
1213
"response":{
1314
"status":200
@@ -16,17 +17,18 @@
1617
"origin":"AWS::Lambda"
1718
},
1819
{
20+
"name":"serverlessrepo-aot-py38-sar-function-.*",
1921
"origin":"AWS::Lambda::Function",
2022
"subsegments":[
2123
{
2224
"name":"Invocation",
2325
"subsegments":[
2426
{
25-
"name":"lambda_function.lambda_handler",
27+
"name":"lambda_function\\.lambda_handler",
2628
"aws":{
2729
"xray":{
2830
"auto_instrumentation":false,
29-
"sdk_version":"0.16b1",
31+
"sdk_version":"0\\.16b1",
3032
"sdk":"opentelemetry for python"
3133
}
3234
}
@@ -44,7 +46,7 @@
4446
"inferred":true,
4547
"http":{
4648
"request":{
47-
"url":"http://httpbin.org/",
49+
"url":"http://httpbin\\.org/",
4850
"method":"GET"
4951
}
5052
}

validator/src/main/resources/expected-data-template/otelSDKexpectedHTTPTrace.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"name": "HTTP GET",
1919
"http": {
2020
"request": {
21-
"url": "https://aws.amazon.com/",
21+
"url": "https://aws\\.amazon\\.com/",
2222
"method": "GET"
2323
},
2424
"response": {

validator/src/main/resources/expected-data-template/xraySDKexpectedHTTPTrace.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"name": "aws.amazon.com",
1414
"http": {
1515
"request": {
16-
"url": "https://aws.amazon.com",
16+
"url": "https://aws\\.amazon\\.com",
1717
"method": "get"
1818
}
1919
},

0 commit comments

Comments
 (0)