Skip to content

Commit 481947a

Browse files
committed
@IgnoreNonStaticTraceComponent annotation for instance-specific tracing
1 parent e9fa577 commit 481947a

File tree

6 files changed

+165
-89
lines changed

6 files changed

+165
-89
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* IBM Corporation - initial API and implementation
12+
*******************************************************************************/
13+
14+
package com.ibm.websphere.ras.annotation;
15+
16+
import static java.lang.annotation.ElementType.FIELD;
17+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
18+
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.Target;
21+
22+
/**
23+
* Indicates that a non-static TraceComponent field should be ignored by the
24+
* Liberty bytecode instrumentation tool. This annotation is used in cases where
25+
* a TraceComponent must be instance-specific (non-static) for legitimate reasons,
26+
* such as when different instances need different trace channels or configurations.
27+
* <p>
28+
* Without this annotation, the instrumentation tool will issue a warning and fail
29+
* instrumentation when it encounters a non-static TraceComponent field, as the
30+
* standard pattern requires TraceComponent fields to be declared as
31+
* {@code private static final}.
32+
* <p>
33+
* Example usage:
34+
* <pre>
35+
* public class MyClass {
36+
* // Dummy static TraceComponent to satisfy instrumentation
37+
* private static final TraceComponent tc = Tr.register(MyClass.class);
38+
*
39+
* // Instance-specific TraceComponent that won't trigger instrumentation errors
40+
* &#64;IgnoreNonStaticTraceComponent
41+
* private final TraceComponent instanceTc;
42+
*
43+
* public MyClass(String channelName) {
44+
* this.instanceTc = Tr.register(channelName, MyClass.class, TRACE_GROUP);
45+
* }
46+
* }
47+
* </pre>
48+
*
49+
* @see com.ibm.websphere.ras.TraceComponent
50+
* @see com.ibm.websphere.ras.Tr
51+
*/
52+
@Target({ FIELD })
53+
@Retention(RUNTIME)
54+
public @interface IgnoreNonStaticTraceComponent {}

dev/com.ibm.ws.persistence/src/com/ibm/wsspi/persistence/internal/eclipselink/LogChannel.java

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,21 @@
1616

1717
import com.ibm.websphere.ras.Tr;
1818
import com.ibm.websphere.ras.TraceComponent;
19+
import com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent;
1920
import com.ibm.websphere.ras.annotation.Trivial;
2021
import com.ibm.wsspi.persistence.internal.PersistenceServiceConstants;
2122

2223
//TODO(151905) -- Cleanup. Poached from Liberty
2324
@Trivial
2425
class LogChannel {
25-
/*
26-
* WORKAROUND for Liberty bytecode instrumentation limitation:
27-
*
28-
* The instrumentation tool requires TraceComponent fields to be 'private static final'.
29-
* However, this class needs instance-specific trace components for different EclipseLink channels.
30-
*
31-
* Solution: Declare a dummy static TraceComponent to satisfy instrumentation, then store
32-
* the actual instance TraceComponent as Object type (which instrumentation doesn't check).
33-
* The _tc() helper method casts it back to TraceComponent when needed for logging.
34-
*/
26+
// Static TraceComponent for general LogChannel class tracing
3527
private static final TraceComponent _stc = Tr.register(LogChannel.class);
36-
private final Object _tcInstance;
3728

38-
private TraceComponent _tc() {
39-
return (TraceComponent) _tcInstance;
40-
}
29+
// Instance-specific TraceComponent for different EclipseLink channels
30+
// The @IgnoreNonStaticTraceComponent annotation tells the instrumentation tool
31+
// that this non-static field is intentional and should not trigger warnings
32+
@IgnoreNonStaticTraceComponent
33+
private final TraceComponent _tc;
4134

4235
/**
4336
* Log levels (per EclipseLink)
@@ -57,29 +50,29 @@ private TraceComponent _tc() {
5750
*/
5851
LogChannel(String channel) {
5952
// Register a TraceComponent for this specific channel
60-
_tcInstance = Tr.register(channel, LogChannel.class, PersistenceServiceConstants.TRACE_GROUP);
53+
_tc = Tr.register(channel, LogChannel.class, PersistenceServiceConstants.TRACE_GROUP);
6154
}
6255

6356
boolean shouldLog(int level) {
6457
switch (level) {
6558
case 8:
6659
return false;
6760
case 7: // SEVERE
68-
return _tc().isErrorEnabled();
61+
return _tc.isErrorEnabled();
6962
case 6: // WARN
70-
return _tc().isWarningEnabled();
63+
return _tc.isWarningEnabled();
7164
case 5: // INFO
72-
return _tc().isInfoEnabled();
65+
return _tc.isInfoEnabled();
7366
case 4: // CONFIG
74-
return _tc().isConfigEnabled();
67+
return _tc.isConfigEnabled();
7568
case 3: // FINE
76-
return _tc().isEventEnabled();
69+
return _tc.isEventEnabled();
7770
case 2: // FINER
78-
return _tc().isEntryEnabled();
71+
return _tc.isEntryEnabled();
7972
case 1: // FINEST
8073
case 0: // TRACE
8174
default:
82-
return _tc().isDebugEnabled();
75+
return _tc.isDebugEnabled();
8376
}// end switch
8477
}
8578

@@ -103,23 +96,23 @@ void log(SessionLogEntry entry, String formattedMessage) {
10396
case 7: // SEVERE
10497
// With the persistence service, only errors will be logged. The rest will be debug.
10598
String errMsg = Tr.formatMessage(_stc, "PROVIDER_ERROR_CWWKD0292E", msgParm);
106-
Tr.error(_tc(), errMsg);
99+
Tr.error(_tc, errMsg);
107100
break;
108101
case 6:// WARN
109102
String wrnMsg = Tr.formatMessage(_stc, "PROVIDER_WARNING_CWWKD0291W", msgParm);
110-
Tr.debug(_tc(), wrnMsg); // 170432 - move warnings to debug
103+
Tr.debug(_tc, wrnMsg); // 170432 - move warnings to debug
111104
break;
112105
case 3: // FINE
113106
case 2: // FINER
114107
case 1: // FINEST
115108
case 0: // TRACE
116-
Tr.debug(_tc(), formattedMessage);
109+
Tr.debug(_tc, formattedMessage);
117110
break;
118111
}// end switch
119112

120113
// if there is an exception - only log it to trace
121-
if (_tc().isDebugEnabled() && loggedException != null) {
122-
Tr.debug(_tc(), "throwable", loggedException);
114+
if (_tc.isDebugEnabled() && loggedException != null) {
115+
Tr.debug(_tc, "throwable", loggedException);
123116
}
124117
}
125118
}

dev/com.ibm.ws.ras.instrument/src/com/ibm/ws/ras/instrument/internal/introspect/TraceConfigClassVisitor.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class TraceConfigClassVisitor extends ClassVisitor {
4242
protected final static Type TRIVIAL_TYPE = Type.getType(com.ibm.websphere.ras.annotation.Trivial.class);;
4343
protected final static Type FFDC_IGNORE_TYPE = Type.getType(com.ibm.ws.ffdc.annotation.FFDCIgnore.class);
4444
protected final static Type TRACE_OBJECT_FIELD_TYPE = Type.getType(com.ibm.websphere.ras.annotation.TraceObjectField.class);
45+
protected final static Type IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE = Type.getType(com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent.class);
4546

4647
protected ClassInfo classInfo;
4748
protected TraceOptionsAnnotationVisitor traceOptionsAnnotationVisitor;
@@ -85,7 +86,34 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
8586
FieldInfo fieldInfo = new FieldInfo(name, desc);
8687
classInfo.addFieldInfo(fieldInfo);
8788
}
88-
return fv;
89+
return new FieldInfoFieldVisitor(fv, name, desc, access);
90+
}
91+
92+
private final static class FieldInfoFieldVisitor extends FieldVisitor {
93+
private final String fieldName;
94+
private final String fieldDesc;
95+
private final int fieldAccess;
96+
private boolean hasIgnoreAnnotation = false;
97+
98+
private FieldInfoFieldVisitor(FieldVisitor fv, String name, String desc, int access) {
99+
super(ASMHelper.getCurrentASM(), fv);
100+
this.fieldName = name;
101+
this.fieldDesc = desc;
102+
this.fieldAccess = access;
103+
}
104+
105+
@Override
106+
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
107+
AnnotationVisitor av = super.visitAnnotation(desc, visible);
108+
if (IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE.getDescriptor().equals(desc)) {
109+
hasIgnoreAnnotation = true;
110+
}
111+
return av;
112+
}
113+
114+
public boolean hasIgnoreAnnotation() {
115+
return hasIgnoreAnnotation;
116+
}
89117
}
90118

91119
@Override

dev/com.ibm.ws.ras.instrument/src/com/ibm/ws/ras/instrument/internal/main/LibertyTracePreprocessInstrumentation.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public class LibertyTracePreprocessInstrumentation extends AbstractInstrumentati
7777
public final static Type INJECTED_TRACE_TYPE = Type.getType(com.ibm.websphere.ras.annotation.InjectedTrace.class);
7878
public final static Type MANUAL_TRACE_TYPE = Type.getType(com.ibm.websphere.ras.annotation.ManualTrace.class);
7979
public final static Type TRACE_OBJECT_FIELD_TYPE = Type.getType(com.ibm.websphere.ras.annotation.TraceObjectField.class);
80+
public final static Type IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE = Type.getType(com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent.class);
8081

8182
private boolean addFfdc = false;
8283
private boolean injectStatic = false;
@@ -257,7 +258,7 @@ private void processClassTraceOptionsAnnotation(ClassTraceInfo info) {
257258
/**
258259
* Introspect the class to obtain the list of fields declared as {@code com.ibm.websphere.ras.TraceComponent}s. Only static
259260
* declarations are considered.
260-
*
261+
*
261262
* @param info the collected class information
262263
*/
263264
private void processLibertyTraceComponentDiscovery(ClassTraceInfo info) {
@@ -267,13 +268,27 @@ private void processLibertyTraceComponentDiscovery(ClassTraceInfo info) {
267268
for (int i = traceComponentFields.size() - 1; i >= 0; i--) {
268269
FieldNode fn = traceComponentFields.get(i);
269270
if ((fn.access & Opcodes.ACC_STATIC) != Opcodes.ACC_STATIC) {
270-
// Trace Component fields found, but not static
271+
// Check if the field has the @IgnoreNonStaticTraceComponent annotation
272+
boolean hasIgnoreAnnotation = false;
273+
if (fn.visibleAnnotations != null) {
274+
for (AnnotationNode an : fn.visibleAnnotations) {
275+
if (IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE.getDescriptor().equals(an.desc)) {
276+
hasIgnoreAnnotation = true;
277+
break;
278+
}
279+
}
280+
}
281+
282+
// Trace Component fields found, but not static
271283
traceComponentFields.remove(i);
272-
StringBuilder sb = new StringBuilder();
273-
sb.append("WARNING: TraceComponent field declared but must be static in class: ");
274-
sb.append(info.classNode.name.replaceAll("/", "\\."));
275-
info.warnings.add(sb.toString());
276-
info.failInstrumentation = true;
284+
285+
if (!hasIgnoreAnnotation) {
286+
StringBuilder sb = new StringBuilder();
287+
sb.append("WARNING: TraceComponent field declared but must be static in class: ");
288+
sb.append(info.classNode.name.replaceAll("/", "\\."));
289+
info.warnings.add(sb.toString());
290+
info.failInstrumentation = true;
291+
}
277292
}
278293
}
279294
if (traceComponentFields.size() > 1) {

dev/com.ibm.ws.security.oauth/src/com/ibm/ws/security/oauth20/error/impl/BrowserAndServerLogMessage.java

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.ibm.websphere.ras.Tr;
1919
import com.ibm.websphere.ras.TraceComponent;
20+
import com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent;
2021
import com.ibm.ws.security.common.lang.LocalesModifier;
2122

2223
/**
@@ -25,39 +26,31 @@
2526
* other line is updated at some point.
2627
*/
2728
public class BrowserAndServerLogMessage {
28-
/*
29-
* WORKAROUND for Liberty bytecode instrumentation limitation:
30-
*
31-
* The instrumentation tool requires TraceComponent fields to be 'private static final'.
32-
* However, this class needs instance-specific trace components to support different
33-
* OAuth providers and localized error messages.
34-
*
35-
* Solution: Declare a dummy static TraceComponent to satisfy instrumentation, then store
36-
* the actual instance TraceComponent as Object type (which instrumentation doesn't check).
37-
* The tc() helper method casts it back to TraceComponent when needed for message formatting.
38-
*/
29+
// Static TraceComponent for general class tracing
3930
private static final TraceComponent tcStatic = Tr.register(BrowserAndServerLogMessage.class);
40-
private final Object tcInstance;
31+
32+
// Instance-specific TraceComponent for different OAuth providers
33+
// The @IgnoreNonStaticTraceComponent annotation tells the instrumentation tool
34+
// that this non-static field is intentional and should not trigger warnings
35+
@IgnoreNonStaticTraceComponent
36+
private final TraceComponent tc;
37+
4138
private Enumeration<Locale> requestLocales = null;
4239
private final String msgKey;
4340
private final Object[] inserts;
4441

4542
public BrowserAndServerLogMessage(TraceComponent tc, String msgKey, Object... inserts) {
46-
this.tcInstance = tc;
43+
this.tc = tc;
4744
this.msgKey = msgKey;
4845
this.inserts = inserts;
4946
}
50-
51-
private TraceComponent tc() {
52-
return (TraceComponent) tcInstance;
53-
}
5447

5548
public String getBrowserErrorMessage() {
56-
return Tr.formatMessage(tc(), LocalesModifier.getPrimaryLocale(requestLocales), msgKey, inserts);
49+
return Tr.formatMessage(tc, LocalesModifier.getPrimaryLocale(requestLocales), msgKey, inserts);
5750
}
5851

5952
public String getServerErrorMessage() {
60-
return Tr.formatMessage(tc(), msgKey, inserts);
53+
return Tr.formatMessage(tc, msgKey, inserts);
6154
}
6255

6356
public void setLocales(Enumeration<Locale> requestLocales) {

0 commit comments

Comments
 (0)