Skip to content

Commit 6cb20fe

Browse files
committed
Add TraceIdentifierMapAdapter for optimizing Log4j2 correlation
1 parent fa47ee7 commit 6cb20fe

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package co.elastic.apm.agent.log.shader;
2+
3+
import co.elastic.apm.agent.impl.GlobalTracer;
4+
import co.elastic.apm.agent.impl.Tracer;
5+
import co.elastic.apm.agent.impl.transaction.Span;
6+
import co.elastic.apm.agent.impl.transaction.Transaction;
7+
8+
import javax.annotation.Nullable;
9+
import java.util.AbstractMap;
10+
import java.util.AbstractSet;
11+
import java.util.Arrays;
12+
import java.util.Iterator;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.NoSuchElementException;
16+
import java.util.Set;
17+
import java.util.concurrent.Callable;
18+
19+
public class TraceIdentifierMapAdapter extends AbstractMap<String, String> {
20+
21+
private static final TraceIdentifierMapAdapter INSTANCE = new TraceIdentifierMapAdapter();
22+
23+
private static final Set<Entry<String, String>> ENTRY_SET = new TraceIdentifierEntrySet();
24+
private static final List<String> ALL_KEYS = Arrays.asList("trace.id", "transaction.id", "span.id");
25+
private static final Tracer tracer = GlobalTracer.get();
26+
private static final List<Entry<String, String>> ENTRIES = Arrays.asList(
27+
new LazyEntry("trace.id", new Callable<String>() {
28+
@Override
29+
@Nullable
30+
public String call() {
31+
Transaction transaction = tracer.currentTransaction();
32+
if (transaction == null) {
33+
return null;
34+
}
35+
return transaction.getTraceContext().getTraceId().toString();
36+
}
37+
}),
38+
new LazyEntry("transaction.id", new Callable<String>() {
39+
@Override
40+
@Nullable
41+
public String call() {
42+
Transaction transaction = tracer.currentTransaction();
43+
if (transaction == null) {
44+
return null;
45+
}
46+
return transaction.getTraceContext().getId().toString();
47+
}
48+
}),
49+
new LazyEntry("span.id", new Callable<String>() {
50+
@Override
51+
@Nullable
52+
public String call() {
53+
Span span = tracer.getActiveSpan();
54+
if (span == null) {
55+
return null;
56+
}
57+
return span.getTraceContext().getId().toString();
58+
}
59+
})
60+
);
61+
62+
public static Map<String, String> get() {
63+
return INSTANCE;
64+
}
65+
66+
private TraceIdentifierMapAdapter() {
67+
}
68+
69+
@Override
70+
public Set<Entry<String, String>> entrySet() {
71+
return ENTRY_SET;
72+
}
73+
74+
public Iterable<String> allKeys() {
75+
return ALL_KEYS;
76+
}
77+
78+
private static class TraceIdentifierEntrySet extends AbstractSet<Entry<String, String>> {
79+
80+
@Override
81+
public int size() {
82+
int size = 0;
83+
for (Entry<String, String> ignored : this) {
84+
size++;
85+
}
86+
return size;
87+
}
88+
89+
@Override
90+
public Iterator<Entry<String, String>> iterator() {
91+
return new Iterator<Entry<String, String>>() {
92+
private int i = 0;
93+
@Nullable
94+
private Entry<String, String> next = findNext();
95+
96+
@Override
97+
public boolean hasNext() {
98+
return next != null;
99+
}
100+
101+
@Override
102+
public Entry<String, String> next() {
103+
if (next != null) {
104+
try {
105+
return next;
106+
} finally {
107+
next = findNext();
108+
}
109+
} else {
110+
throw new NoSuchElementException();
111+
}
112+
}
113+
114+
@Nullable
115+
private Entry<String, String> findNext() {
116+
Entry<String, String> next = null;
117+
while (next == null && i < ENTRIES.size()) {
118+
next = ENTRIES.get(i++);
119+
if (next.getValue() == null) {
120+
next = null;
121+
}
122+
}
123+
return next;
124+
}
125+
};
126+
}
127+
128+
}
129+
130+
private static class LazyEntry implements Entry<String, String> {
131+
private final String key;
132+
private final Callable<String> valueSupplier;
133+
134+
private LazyEntry(String key, Callable<String> valueSupplier) {
135+
this.key = key;
136+
this.valueSupplier = valueSupplier;
137+
}
138+
139+
@Override
140+
public String getKey() {
141+
return this.key;
142+
}
143+
144+
@Override
145+
public String getValue() {
146+
try {
147+
return this.valueSupplier.call();
148+
} catch (Exception e) {
149+
throw new RuntimeException(e);
150+
}
151+
}
152+
153+
@Override
154+
public String setValue(String value) {
155+
throw new UnsupportedOperationException();
156+
}
157+
}
158+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package co.elastic.apm.agent.log.shader;
2+
3+
import co.elastic.apm.agent.MockTracer;
4+
import co.elastic.apm.agent.impl.ElasticApmTracer;
5+
import co.elastic.apm.agent.impl.GlobalTracer;
6+
import co.elastic.apm.agent.impl.Scope;
7+
import co.elastic.apm.agent.impl.transaction.Span;
8+
import co.elastic.apm.agent.impl.transaction.Transaction;
9+
import org.junit.jupiter.api.AfterEach;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
15+
16+
class TraceIdentifierMapAdapterTest {
17+
18+
private ElasticApmTracer tracer = MockTracer.createRealTracer();
19+
20+
@BeforeEach
21+
void setUp() {
22+
GlobalTracer.init(tracer);
23+
}
24+
25+
@AfterEach
26+
void tearDown() {
27+
tracer.stop();
28+
GlobalTracer.setNoop();
29+
}
30+
31+
@Test
32+
void testNoContext() {
33+
assertThat(TraceIdentifierMapAdapter.get()).isEmpty();
34+
}
35+
36+
@Test
37+
void testTransactionContext() {
38+
Transaction transaction = tracer.startRootTransaction(null);
39+
try (Scope scope = transaction.activateInScope()) {
40+
assertThat(TraceIdentifierMapAdapter.get()).containsOnlyKeys("trace.id", "transaction.id");
41+
} finally {
42+
transaction.end();
43+
}
44+
assertThat(TraceIdentifierMapAdapter.get()).isEmpty();
45+
}
46+
47+
@Test
48+
void testSpanContext() {
49+
Transaction transaction = tracer.startRootTransaction(null);
50+
Span span = transaction.createSpan();
51+
try (Scope scope = span.activateInScope()) {
52+
assertThat(TraceIdentifierMapAdapter.get()).containsOnlyKeys("trace.id", "transaction.id", "span.id");
53+
} finally {
54+
span.end();
55+
}
56+
transaction.end();
57+
assertThat(TraceIdentifierMapAdapter.get()).isEmpty();
58+
}
59+
}

0 commit comments

Comments
 (0)