10
10
import io .opentelemetry .instrumentation .jdbc .datasource .JdbcTelemetry ;
11
11
import io .opentelemetry .instrumentation .spring .autoconfigure .internal .properties .InstrumentationConfigUtil ;
12
12
import io .opentelemetry .sdk .autoconfigure .spi .ConfigProperties ;
13
+ import java .io .PrintWriter ;
14
+ import java .sql .Connection ;
15
+ import java .sql .SQLException ;
16
+ import java .sql .SQLFeatureNotSupportedException ;
17
+ import java .util .logging .Logger ;
13
18
import javax .sql .DataSource ;
19
+ import org .springframework .aop .SpringProxy ;
20
+ import org .springframework .aop .framework .AdvisedSupport ;
14
21
import org .springframework .aop .scope .ScopedProxyUtils ;
15
22
import org .springframework .beans .factory .ObjectProvider ;
16
23
import org .springframework .beans .factory .config .BeanPostProcessor ;
@@ -50,22 +57,28 @@ public Object postProcessAfterInitialization(Object bean, String beanName) {
50
57
&& !isRoutingDatasource (bean )
51
58
&& !ScopedProxyUtils .isScopedTarget (beanName )) {
52
59
DataSource dataSource = (DataSource ) bean ;
53
- return JdbcTelemetry .builder (openTelemetryProvider .getObject ())
54
- .setStatementSanitizationEnabled (
55
- InstrumentationConfigUtil .isStatementSanitizationEnabled (
56
- configPropertiesProvider .getObject (),
57
- "otel.instrumentation.jdbc.statement-sanitizer.enabled" ))
58
- .setCaptureQueryParameters (
59
- configPropertiesProvider
60
- .getObject ()
61
- .getBoolean (
62
- "otel.instrumentation.jdbc.experimental.capture-query-parameters" , false ))
63
- .setTransactionInstrumenterEnabled (
64
- configPropertiesProvider
65
- .getObject ()
66
- .getBoolean ("otel.instrumentation.jdbc.experimental.transaction.enabled" , false ))
67
- .build ()
68
- .wrap (dataSource );
60
+ DataSource otelDataSource =
61
+ JdbcTelemetry .builder (openTelemetryProvider .getObject ())
62
+ .setStatementSanitizationEnabled (
63
+ InstrumentationConfigUtil .isStatementSanitizationEnabled (
64
+ configPropertiesProvider .getObject (),
65
+ "otel.instrumentation.jdbc.statement-sanitizer.enabled" ))
66
+ .setCaptureQueryParameters (
67
+ configPropertiesProvider
68
+ .getObject ()
69
+ .getBoolean (
70
+ "otel.instrumentation.jdbc.experimental.capture-query-parameters" , false ))
71
+ .setTransactionInstrumenterEnabled (
72
+ configPropertiesProvider
73
+ .getObject ()
74
+ .getBoolean (
75
+ "otel.instrumentation.jdbc.experimental.transaction.enabled" , false ))
76
+ .build ()
77
+ .wrap (dataSource );
78
+
79
+ // wrap instrumented data source into a proxy that unwraps to the original data source
80
+ // see https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/13512
81
+ return new DataSource$$Wrapper (otelDataSource , dataSource );
69
82
}
70
83
return bean ;
71
84
}
@@ -75,4 +88,65 @@ public Object postProcessAfterInitialization(Object bean, String beanName) {
75
88
public int getOrder () {
76
89
return Ordered .LOWEST_PRECEDENCE - 20 ;
77
90
}
91
+
92
+ // Wrapper for DataSource that pretends to be a spring aop proxy. $$ in class name is commonly
93
+ // used by bytecode proxies and is tested by
94
+ // org.springframework.aop.support.AopUtils.isAopProxy(). This proxy can be unwrapped with
95
+ // ((Advised) dataSource).getTargetSource().getTarget() and it unwraps to the original data
96
+ // source.
97
+ @ SuppressWarnings ("checkstyle:TypeName" )
98
+ private static class DataSource$$Wrapper extends AdvisedSupport
99
+ implements SpringProxy , DataSource {
100
+ private final DataSource delegate ;
101
+
102
+ DataSource$$Wrapper (DataSource delegate , DataSource original ) {
103
+ this .delegate = delegate ;
104
+ setTarget (original );
105
+ }
106
+
107
+ @ Override
108
+ public Connection getConnection () throws SQLException {
109
+ return delegate .getConnection ();
110
+ }
111
+
112
+ @ Override
113
+ public Connection getConnection (String username , String password ) throws SQLException {
114
+ return delegate .getConnection (username , password );
115
+ }
116
+
117
+ @ Override
118
+ public PrintWriter getLogWriter () throws SQLException {
119
+ return delegate .getLogWriter ();
120
+ }
121
+
122
+ @ Override
123
+ public void setLogWriter (PrintWriter out ) throws SQLException {
124
+ delegate .setLogWriter (out );
125
+ }
126
+
127
+ @ Override
128
+ public void setLoginTimeout (int seconds ) throws SQLException {
129
+ delegate .setLoginTimeout (seconds );
130
+ }
131
+
132
+ @ Override
133
+ public int getLoginTimeout () throws SQLException {
134
+ return delegate .getLoginTimeout ();
135
+ }
136
+
137
+ @ Override
138
+ public Logger getParentLogger () throws SQLFeatureNotSupportedException {
139
+ return delegate .getParentLogger ();
140
+ }
141
+
142
+ @ Override
143
+ public <T > T unwrap (Class <T > iface ) throws SQLException {
144
+ return delegate .unwrap (iface );
145
+ }
146
+
147
+ @ Override
148
+ public boolean isWrapperFor (Class <?> iface ) throws SQLException {
149
+ return delegate .isWrapperFor (iface );
150
+ }
151
+ }
78
152
}
0 commit comments