Skip to content

Commit 1c08899

Browse files
committed
Adding additional support for b3multi propagator
1 parent 0565cdc commit 1c08899

File tree

6 files changed

+128
-21
lines changed

6 files changed

+128
-21
lines changed

Diff for: dev/com.ibm.ws.logging/src/com/ibm/ws/logging/collector/CollectorConstants.java

+3
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,8 @@ public class CollectorConstants {
5252
public static final String ACCESS_TRACE_W3C_HEADER_NAME = "traceparent";
5353
public static final String ACCESS_TRACE_JAEGER_HEADER_NAME = "uber-trace-id";
5454
public static final String ACCESS_TRACE_B3_HEADER_NAME = "b3";
55+
public static final String ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME = "X-B3-TraceId";
56+
public static final String ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME = "X-B3-SpanId";
57+
public static final String ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME = "X-B3-Sampled";
5558

5659
}

Diff for: dev/com.ibm.ws.transport.http/src/com/ibm/ws/http/logging/source/AccessLogSource.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,15 @@ private static SetterFormatter createSetterFormatter(Configuration config, Forma
603603
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_JAEGER_HEADER_NAME,
604604
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
605605
CollectorConstants.ACCESS_TRACE_JAEGER_HEADER_NAME)));
606+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME,
607+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
608+
CollectorConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME)));
609+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME,
610+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
611+
CollectorConstants.ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME)));
612+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME,
613+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
614+
CollectorConstants.ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME)));
606615

607616
} else if (accessLogFieldsTelemetryConfig.equals("logFormat")) {
608617
formatters[5] = populateCustomTelemetryFormatters(fieldsToAddTelemetryLogging, CollectorConstants.KEYS_TELEMETRY_LOGGING);
@@ -618,7 +627,15 @@ private static SetterFormatter createSetterFormatter(Configuration config, Forma
618627
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_JAEGER_HEADER_NAME,
619628
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
620629
CollectorConstants.ACCESS_TRACE_JAEGER_HEADER_NAME)));
621-
630+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME,
631+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
632+
CollectorConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME)));
633+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME,
634+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
635+
CollectorConstants.ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME)));
636+
fieldSetters.add((ald, alrd) -> ald.setRequestHeader(CollectorConstants.ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME,
637+
AccessLogRequestHeaderValue.getHeaderValue(alrd.getResponse(), alrd.getRequest(),
638+
CollectorConstants.ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME)));
622639
}
623640

624641
newSF.setSettersAndFormatters(fieldSetters, formatters);

Diff for: dev/io.openliberty.microprofile.telemetry.2.0.logging.internal/src/io/openliberty/microprofile/telemetry20/logging/internal/MpTelemetryLogFieldConstants.java

+3
Original file line numberDiff line numberDiff line change
@@ -155,5 +155,8 @@ public class MpTelemetryLogFieldConstants {
155155
public static final String ACCESS_TRACE_W3C_HEADER_NAME = "traceparent";
156156
public static final String ACCESS_TRACE_JAEGER_HEADER_NAME = "uber-trace-id";
157157
public static final String ACCESS_TRACE_B3_HEADER_NAME = "b3";
158+
public static final String ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME = "X-B3-TraceId";
159+
public static final String ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME = "X-B3-SpanId";
160+
public static final String ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME = "X-B3-Sampled";
158161

159162
}

Diff for: dev/io.openliberty.microprofile.telemetry.2.0.logging.internal/src/io/openliberty/microprofile/telemetry20/logging/internal/MpTelemetryLogMappingUtils.java

+38-5
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ private static void mapAccessToOpenTelemetry(LogRecordBuilder builder, String ev
348348
Object value = null;
349349
Span customSpan = null;
350350

351+
String b3MultiTrace = null;
352+
String b3MultiSpan = null;
353+
String b3MultiSampling = null;
354+
351355
for (Iterator<KeyValuePair> element = kvpList.iterator(); element.hasNext();) {
352356
KeyValuePair next = element.next();
353357
key = next.getKey();
@@ -366,6 +370,12 @@ private static void mapAccessToOpenTelemetry(LogRecordBuilder builder, String ev
366370
if (key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_W3C_HEADER_NAME) || key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_HEADER_NAME)
367371
|| key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_JAEGER_HEADER_NAME)) {
368372
customSpan = createSpan(key, (String) value);
373+
} else if (key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME)) {
374+
b3MultiSpan = (String) value;
375+
} else if (key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME)) {
376+
b3MultiTrace = (String) value;
377+
} else if (key.contains(MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME)) {
378+
b3MultiSampling = (String) value;
369379
} else {
370380
String[] headerSplit = ((String) value).split(",");
371381
for (int i = 0; i < headerSplit.length; i++) {
@@ -400,8 +410,13 @@ else if (value instanceof Integer)
400410
// Set the Attributes to the builder.
401411
builder.setAllAttributes(attributes.build());
402412

413+
if (customSpan == null && b3MultiSpan != null && b3MultiTrace != null) {
414+
customSpan = createSpan(MpTelemetryLogFieldConstants.ACCESS_REQUEST_HEADER_PREFIX + MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME,
415+
b3MultiTrace + "-" + b3MultiSpan + "-" + b3MultiSampling);
416+
}
417+
403418
// Set the Span and Trace IDs from the current context. We're not on the same thread at the point when access logs are collected
404-
// so we need to extract the trace/span ID from the 'traceparent' request header.
419+
// so we need to extract the trace/span ID from each propagators' respective request headers.
405420
if (customSpan != null) {
406421
builder.setContext(Context.current().with(customSpan));
407422
} else
@@ -410,21 +425,32 @@ else if (value instanceof Integer)
410425
}
411426

412427
/*
413-
* Create a span using the extracted requestHeader data for the propagators w3c, b3, and jaeger.
428+
* Create a span using the extracted requestHeader data for the propagators w3c, b3, b3multi, and jaeger.
414429
*/
415430
private static Span createSpan(String key, String requestHeader) {
416431

417432
SpanContext customSpanContext = null;
418433
try {
419434
if (key.equals(MpTelemetryLogFieldConstants.ACCESS_REQUEST_HEADER_PREFIX + MpTelemetryLogFieldConstants.ACCESS_TRACE_W3C_HEADER_NAME)) { // Check the w3c format for the "traceparent" header. This is the default otel propagator
420435
String[] traceSplit = requestHeader.split("-");
421-
customSpanContext = SpanContext.create(traceSplit[1], traceSplit[2], TraceFlags.getSampled(), TraceState.getDefault());
436+
TraceFlags sampling = isSampledValue(traceSplit[3]) ? TraceFlags.getSampled() : TraceFlags.getDefault();
437+
438+
customSpanContext = SpanContext.create(traceSplit[1], traceSplit[2], sampling, TraceState.getDefault());
422439
} else if (key.equals(MpTelemetryLogFieldConstants.ACCESS_REQUEST_HEADER_PREFIX + MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_HEADER_NAME)) { // Check the b3 format for the "b3" header
423440
String[] traceSplit = requestHeader.split("-");
424-
customSpanContext = SpanContext.create(traceSplit[0], traceSplit[1], TraceFlags.getSampled(), TraceState.getDefault());
441+
TraceFlags sampling = isSampledValue(traceSplit[2]) ? TraceFlags.getSampled() : TraceFlags.getDefault();
442+
443+
customSpanContext = SpanContext.create(traceSplit[0], traceSplit[1], sampling, TraceState.getDefault());
425444
} else if (key.equals(MpTelemetryLogFieldConstants.ACCESS_REQUEST_HEADER_PREFIX + MpTelemetryLogFieldConstants.ACCESS_TRACE_JAEGER_HEADER_NAME)) { // Check the Jaeger format for the "uber-trace-id" header
426445
String[] traceSplit = requestHeader.split(":");
427-
customSpanContext = SpanContext.create(traceSplit[0], traceSplit[1], TraceFlags.getSampled(), TraceState.getDefault());
446+
TraceFlags sampling = isSampledValue(traceSplit[3]) ? TraceFlags.getSampled() : TraceFlags.getDefault();
447+
448+
customSpanContext = SpanContext.create(traceSplit[0], traceSplit[1], sampling, TraceState.getDefault());
449+
} else if (key.equals(MpTelemetryLogFieldConstants.ACCESS_REQUEST_HEADER_PREFIX + MpTelemetryLogFieldConstants.ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME)) { // Check the Jaeger format for the "uber-trace-id" header
450+
String[] traceSplit = requestHeader.split("-");
451+
TraceFlags sampling = isSampledValue(traceSplit[2]) ? TraceFlags.getSampled() : TraceFlags.getDefault();
452+
453+
customSpanContext = SpanContext.create(traceSplit[0], traceSplit[1], sampling, TraceState.getDefault());
428454
}
429455

430456
} catch (Exception e) {
@@ -441,6 +467,13 @@ private static Span createSpan(String key, String requestHeader) {
441467

442468
}
443469

470+
/*
471+
* Checks to see if the sampling value is enabled.
472+
*/
473+
private static boolean isSampledValue(String sampledValue) {
474+
return "1".equals(sampledValue) || "01".equals(sampledValue);
475+
}
476+
444477
/**
445478
* Maps the Liberty Log levels to the OpenTelemetry Severity.
446479
*

Diff for: dev/io.openliberty.microprofile.telemetry.2.0.logging.internal_2_fat/fat/src/io/openliberty/microprofile/telemetry/logging/internal_fat/TelemetryAccessTest.java

+34
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,40 @@ public void testTelemetryAccessJaegerTraceLogs() throws Exception {
486486
TestUtils.checkJsonMessage(accessLine, expectedAccessFieldsMap);
487487
}
488488

489+
/*
490+
* Verify that the b3 multi propagator is properly associating traces and spans with the access log
491+
*/
492+
@Test
493+
public void testTelemetryAccessB3MultiTraceLogs() throws Exception {
494+
RemoteFile messageLogFile = server.getDefaultLogFile();
495+
RemoteFile consoleLogFile = server.getConsoleLogFile();
496+
497+
// Configure access feature and access source
498+
setConfig(server, messageLogFile, SERVER_XML_ACCESS_SOURCE_DEFAULT);
499+
500+
// Trigger an access log event
501+
TestUtils.runAccessApp(server, "runAccessApp", "b3multi");
502+
503+
// Wait for the access log message to be bridged over
504+
String accessLine = server.waitForStringInLog("INFO2 'GET /MpTelemetryLogApp/AccessURL HTTP/1.1'", consoleLogFile);
505+
assertFalse("The access log event does NOT contain a valid trace and span id", accessLine.contains(ZERO_SPAN_TRACE_ID));
506+
507+
// Check if the expected key-value pair is correctly formatted and mapped to OTel.
508+
Map<String, String> expectedAccessFieldsMap = new HashMap<String, String>() {
509+
{
510+
put("http.request.method", "GET");
511+
put("http.response.status_code", "200");
512+
put("io.openliberty.access_log.url.path", "/MpTelemetryLogApp/AccessURL");
513+
put("network.local.port", Integer.toString(server.getHttpDefaultPort()));
514+
put("io.openliberty.type", "liberty_accesslog");
515+
put("network.protocol.name", "HTTP");
516+
put("network.protocol.version", "1.1");
517+
put("io.openliberty.sequence", ""); // since, the sequence can be random, have to make sure the sequence field is still present.
518+
}
519+
};
520+
TestUtils.checkJsonMessage(accessLine, expectedAccessFieldsMap);
521+
}
522+
489523
/*
490524
* Verify that invalid trace headers are properly handled and a debug message is logged.
491525
*/

Diff for: dev/io.openliberty.microprofile.telemetry.2.0.logging.internal_2_fat/fat/src/io/openliberty/microprofile/telemetry/logging/internal_fat/TestUtils.java

+32-15
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@ public class TestUtils {
4242
public static String W3C_TRACE_DATA = "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01";
4343
public static String B3_TRACE_DATA = "e5fee0b8184e2a838aafe4aa959aa21c-4626864da5e71e37-1";
4444
public static String JAEGER_TRACE_DATA = "322b8ac131b128bcaf56c0c41b84aff5:956ff8b1abbd7993:0:1";
45+
public static String B3_MULTI_TRACE_DATA = "0af7651916cd43dd8448eb211c80319c";
46+
public static String B3_MULTI_SPAN_DATA = "b9c7c989f97918e1";
47+
public static String B3_MULTI_SAMPLING_DATA = "1";
4548
public static final String ACCESS_TRACE_W3C_HEADER_NAME = "traceparent";
4649
public static final String ACCESS_TRACE_JAEGER_HEADER_NAME = "uber-trace-id";
4750
public static final String ACCESS_TRACE_B3_HEADER_NAME = "b3";
51+
public static final String ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME = "X-B3-TraceId";
52+
public static final String ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME = "X-B3-SpanId";
53+
public static final String ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME = "X-B3-Sampled";
4854

4955
public static void runApp(LibertyServer server, String type) {
5056
String url = "http://" + server.getHostname() + ":" + server.getHttpDefaultPort() + "/MpTelemetryLogApp";
@@ -79,33 +85,41 @@ public static void runAccessApp(LibertyServer server, String type, String propag
7985
String url = "http://" + server.getHostname() + ":" + server.getHttpDefaultPort() + "/MpTelemetryLogApp/AccessURL";
8086
Log.info(c, "runApp", "---> Running the application with url : " + url);
8187

82-
String requestHeader = null;
83-
String traceData = null;
88+
ArrayList<String> requestHeaders = new ArrayList<String>();
89+
ArrayList<String> requestValues = new ArrayList<String>();
90+
8491
if (propagator.equals("w3c")) {
85-
requestHeader = ACCESS_TRACE_W3C_HEADER_NAME;
86-
traceData = W3C_TRACE_DATA;
92+
requestHeaders.add(ACCESS_TRACE_W3C_HEADER_NAME);
93+
requestValues.add(W3C_TRACE_DATA);
8794
} else if (propagator.equals("b3")) {
88-
requestHeader = ACCESS_TRACE_B3_HEADER_NAME;
89-
traceData = B3_TRACE_DATA;
95+
requestHeaders.add(ACCESS_TRACE_B3_HEADER_NAME);
96+
requestValues.add(B3_TRACE_DATA);
9097
} else if (propagator.equals("jaeger")) {
91-
requestHeader = ACCESS_TRACE_JAEGER_HEADER_NAME;
92-
traceData = JAEGER_TRACE_DATA;
98+
requestHeaders.add(ACCESS_TRACE_JAEGER_HEADER_NAME);
99+
requestValues.add(JAEGER_TRACE_DATA);
100+
} else if (propagator.equals("b3multi")) {
101+
requestHeaders.add(ACCESS_TRACE_B3_MULTI_TRACE_HEADER_NAME);
102+
requestValues.add(B3_MULTI_TRACE_DATA);
103+
requestHeaders.add(ACCESS_TRACE_B3_MULTI_SPAN_HEADER_NAME);
104+
requestValues.add(B3_MULTI_SPAN_DATA);
105+
requestHeaders.add(ACCESS_TRACE_B3_MULTI_SAMPLING_HEADER_NAME);
106+
requestValues.add(B3_MULTI_SAMPLING_DATA);
93107
} else if (propagator.equals("invalidHeaderValue")) {
94-
requestHeader = ACCESS_TRACE_JAEGER_HEADER_NAME;
95-
traceData = W3C_TRACE_DATA;
108+
requestHeaders.add(ACCESS_TRACE_JAEGER_HEADER_NAME);
109+
requestValues.add(W3C_TRACE_DATA);
96110
}
97111

98112
try {
99-
if (requestHeader != null)
100-
runGetMethod(url, requestHeader, traceData);
113+
if (!requestHeaders.isEmpty())
114+
runGetMethod(url, requestHeaders, requestValues);
101115
else
102116
runGetMethod(url, null, null);
103117
} catch (Exception e) {
104118
Log.info(c, "runApp", " ---> Exception : " + e.getMessage());
105119
}
106120
}
107121

108-
static String runGetMethod(String urlStr, String requestHeader, String requestValue) throws Exception {
122+
static String runGetMethod(String urlStr, ArrayList<String> requestHeaders, ArrayList<String> requestValues) throws Exception {
109123
Log.info(c, "runGetMethod", "URL = " + urlStr);
110124
URL url = new URL(urlStr);
111125
HttpURLConnection con = (HttpURLConnection) url.openConnection();
@@ -115,8 +129,11 @@ static String runGetMethod(String urlStr, String requestHeader, String requestVa
115129
con.setUseCaches(false);
116130
con.setRequestMethod("GET");
117131

118-
if (requestHeader != null) {
119-
con.setRequestProperty(requestHeader, requestValue);
132+
if (requestHeaders != null) {
133+
for (int i = 0; i < requestHeaders.size(); i++) {
134+
con.setRequestProperty(requestHeaders.get(i), requestValues.get(i));
135+
Log.info(c, "settingRequestHeaders", requestHeaders.get(i) + " -- " + requestValues.get(i));
136+
}
120137
}
121138

122139
InputStream is = con.getInputStream();

0 commit comments

Comments
 (0)