Skip to content

Commit f23f1ee

Browse files
committed
Synchronous flow working
1 parent 31b2fde commit f23f1ee

File tree

14 files changed

+924
-7
lines changed

14 files changed

+924
-7
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import com.microsoft.applicationinsights.agent.internal.exporter.AgentSpanExporter;
4040
import com.microsoft.applicationinsights.agent.internal.exporter.ExporterUtils;
4141
import com.microsoft.applicationinsights.agent.internal.httpclient.LazyHttpClient;
42+
import com.microsoft.applicationinsights.agent.internal.keytransaction.KeyTransactionConfigSupplier;
43+
import com.microsoft.applicationinsights.agent.internal.keytransaction.KeyTransactionSpanProcessor;
4244
import com.microsoft.applicationinsights.agent.internal.legacyheaders.AiLegacyHeaderSpanProcessor;
4345
import com.microsoft.applicationinsights.agent.internal.processors.ExporterWithLogProcessor;
4446
import com.microsoft.applicationinsights.agent.internal.processors.ExporterWithSpanProcessor;
@@ -550,6 +552,10 @@ private static SdkTracerProviderBuilder configureTracing(
550552
tracerProvider.addSpanProcessor(new AiLegacyHeaderSpanProcessor());
551553
}
552554

555+
if (KeyTransactionConfigSupplier.KEY_TRANSACTIONS_ENABLED) {
556+
tracerProvider.addSpanProcessor(new KeyTransactionSpanProcessor());
557+
}
558+
553559
return tracerProvider;
554560
}
555561

@@ -745,6 +751,9 @@ private static void drop(
745751

746752
@Override
747753
public void afterAutoConfigure(OpenTelemetrySdk sdk) {
754+
755+
KeyTransactionSpanProcessor.initMeterProvider(sdk.getMeterProvider());
756+
748757
Runtime.getRuntime()
749758
.addShutdownHook(
750759
new Thread(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package com.microsoft.applicationinsights.agent.internal.keytransaction;
2+
3+
import com.azure.json.JsonReader;
4+
import com.azure.json.JsonToken;
5+
import io.opentelemetry.api.common.AttributeKey;
6+
import io.opentelemetry.api.common.Attributes;
7+
import java.io.IOException;
8+
import java.util.List;
9+
10+
public class KeyTransactionConfig {
11+
12+
private String name;
13+
private List<Criterion> startCriteria;
14+
private List<Criterion> endCriteria;
15+
16+
String getName() {
17+
return name;
18+
}
19+
20+
List<Criterion> getStartCriteria() {
21+
return startCriteria;
22+
}
23+
24+
List<Criterion> getEndCriteria() {
25+
return endCriteria;
26+
}
27+
28+
public static KeyTransactionConfig fromJson(JsonReader jsonReader) throws IOException {
29+
return jsonReader.readObject((reader) -> {
30+
KeyTransactionConfig deserializedValue = new KeyTransactionConfig();
31+
32+
while (reader.nextToken() != JsonToken.END_OBJECT) {
33+
String fieldName = reader.getFieldName();
34+
reader.nextToken();
35+
if ("Name".equals(fieldName)) {
36+
deserializedValue.name = reader.getString();
37+
} else if ("StartCriteria".equals(fieldName)) {
38+
deserializedValue.startCriteria = reader.readArray(Criterion::fromJson);
39+
} else if ("EndCriteria".equals(fieldName)) {
40+
deserializedValue.endCriteria = reader.readArray(Criterion::fromJson);
41+
} else {
42+
reader.skipChildren();
43+
}
44+
}
45+
46+
return deserializedValue;
47+
});
48+
}
49+
50+
public static boolean matches(Attributes attributes, List<Criterion> criteria) {
51+
for (Criterion criterion : criteria) {
52+
String value = attributes.get(criterion.field);
53+
switch (criterion.operator) {
54+
case EQUALS:
55+
if (value == null || !value.equals(criterion.value)) {
56+
return false;
57+
}
58+
break;
59+
case STARTSWITH:
60+
if (value == null || !value.startsWith(criterion.value)) {
61+
return false;
62+
}
63+
break;
64+
case CONTAINS:
65+
if (value == null || !value.contains(criterion.value)) {
66+
return false;
67+
}
68+
break;
69+
default:
70+
// unexpected operator
71+
return false;
72+
}
73+
}
74+
return true;
75+
}
76+
77+
// TODO (not for hackathon) expand this to work with non-String attributes
78+
// a bit tricky since Attributes#get(AttributeKey) requires a known type
79+
// (without iterating over all attributes)
80+
public static class Criterion {
81+
private AttributeKey<String> field;
82+
private String value;
83+
private Operator operator;
84+
85+
// visible for testing
86+
AttributeKey<String> getField() {
87+
return field;
88+
}
89+
90+
// visible for testing
91+
String getValue() {
92+
return value;
93+
}
94+
95+
// visible for testing
96+
Operator getOperator() {
97+
return operator;
98+
}
99+
100+
public static Criterion fromJson(JsonReader jsonReader) throws IOException {
101+
return jsonReader.readObject((reader) -> {
102+
Criterion deserializedValue = new Criterion();
103+
104+
while (reader.nextToken() != JsonToken.END_OBJECT) {
105+
String fieldName = reader.getFieldName();
106+
reader.nextToken();
107+
if ("Field".equals(fieldName)) {
108+
deserializedValue.field = AttributeKey.stringKey(reader.getString());
109+
} else if ("Operator".equals(fieldName)) {
110+
deserializedValue.operator = Operator.from(reader.getString());
111+
} else if ("Value".equals(fieldName)) {
112+
deserializedValue.value = reader.getString();
113+
} else {
114+
reader.skipChildren();
115+
}
116+
}
117+
118+
return deserializedValue;
119+
});
120+
}
121+
}
122+
123+
public enum Operator {
124+
EQUALS, STARTSWITH, CONTAINS;
125+
126+
private static Operator from(String value) {
127+
switch (value) {
128+
case "==":
129+
return EQUALS;
130+
case "startswith":
131+
return STARTSWITH;
132+
case "contains":
133+
return CONTAINS;
134+
default:
135+
throw new IllegalStateException("Unexpected operator: " + value);
136+
}
137+
}
138+
}
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.microsoft.applicationinsights.agent.internal.keytransaction;
2+
3+
import com.azure.json.JsonProviders;
4+
import java.io.IOException;
5+
import java.util.List;
6+
import java.util.function.Supplier;
7+
8+
import static java.util.stream.Collectors.toList;
9+
10+
public class KeyTransactionConfigSupplier implements Supplier<List<KeyTransactionConfig>> {
11+
12+
public static final boolean KEY_TRANSACTIONS_ENABLED = true;
13+
14+
// TODO remove reliance on global
15+
private static final KeyTransactionConfigSupplier instance = new KeyTransactionConfigSupplier();
16+
17+
// static {
18+
// instance.set(hardcodedDemo());
19+
// }
20+
21+
public static KeyTransactionConfigSupplier getInstance() {
22+
return instance;
23+
}
24+
25+
private volatile List<KeyTransactionConfig> configs;
26+
27+
@Override
28+
public List<KeyTransactionConfig> get() {
29+
return configs;
30+
}
31+
32+
public void set(List<KeyTransactionConfig> configs) {
33+
this.configs = configs;
34+
}
35+
36+
@SuppressWarnings("unused")
37+
private static List<KeyTransactionConfig> hardcodedDemo() {
38+
List<KeyTransactionConfig> configs;
39+
try {
40+
configs = NewResponse.fromJson(JsonProviders.createReader(
41+
"{\n"
42+
+ " \"itemsReceived\": 13,\n"
43+
+ " \"itemsAccepted\": 13,\n"
44+
+ " \"appId\": null,\n"
45+
+ " \"errors\": [],\n"
46+
+ " \"sdkConfiguration\": [\n"
47+
+ " {\n"
48+
+ " \"Key\": \"Transaction\",\n"
49+
+ " \"Value\": {\n"
50+
+ " \"Name\": \"EarthOrbit\",\n"
51+
+ " \"StartCriteria\": [\n"
52+
+ " {\n"
53+
+ " \"Field\": \"url.path\",\n"
54+
+ " \"Operator\": \"==\",\n"
55+
+ " \"Value\": \"/earth\"\n"
56+
+ " }\n"
57+
+ " ],\n"
58+
+ " \"EndCriteria\": []\n"
59+
+ " }\n"
60+
+ " },\n"
61+
+ " {\n"
62+
+ " \"Key\": \"Transaction\",\n"
63+
+ " \"Value\": {\n"
64+
+ " \"Name\": \"MarsMission\",\n"
65+
+ " \"StartCriteria\": [\n"
66+
+ " {\n"
67+
+ " \"Field\": \"url.path\",\n"
68+
+ " \"Operator\": \"==\",\n"
69+
+ " \"Value\": \"/mars\"\n"
70+
+ " }\n"
71+
+ " ],\n"
72+
+ " \"EndCriteria\": [\n"
73+
+ " {\n"
74+
+ " \"Field\": \"messaging.todo\",\n"
75+
+ " \"Operator\": \"==\",\n"
76+
+ " \"Value\": \"todo\"\n"
77+
+ " }\n"
78+
+ " ]\n"
79+
+ " }\n"
80+
+ " }\n"
81+
+ " ]\n"
82+
+ "}\n"
83+
))
84+
.getSdkConfigurations()
85+
.stream()
86+
.map(SdkConfiguration::getValue)
87+
.collect(toList());
88+
} catch (IOException e) {
89+
throw new IllegalStateException(e);
90+
}
91+
return configs;
92+
}
93+
}

0 commit comments

Comments
 (0)