6464import org .checkerframework .checker .nullness .qual .Nullable ;
6565
6666@ SuppressWarnings ("DuplicatedCode" )
67- final class OtelStorageDecorator implements Storage {
67+ public final class OtelStorageDecorator implements Storage {
6868
6969 /** Becomes the {@code otel.scope.name} attribute in a span */
7070 private static final String OTEL_SCOPE_NAME = "cloud.google.com/java/storage" ;
7171
72+ private static final String BLOB_READ_SESSION = "blobReadSession" ;
73+
7274 @ VisibleForTesting final Storage delegate ;
7375 private final OpenTelemetry otel ;
7476 private final Attributes baseAttributes ;
@@ -1434,13 +1436,11 @@ public BlobWriteSession blobWriteSession(BlobInfo blobInfo, BlobWriteOption... o
14341436 .startSpan ();
14351437 try (Scope ignore = sessionSpan .makeCurrent ()) {
14361438 BlobWriteSession session = delegate .blobWriteSession (blobInfo , options );
1437- return new OtelDecoratedBlobWriteSession (session );
1439+ return new OtelDecoratedBlobWriteSession (session , sessionSpan );
14381440 } catch (Throwable t ) {
14391441 sessionSpan .recordException (t );
14401442 sessionSpan .setStatus (StatusCode .ERROR , t .getClass ().getSimpleName ());
14411443 throw t ;
1442- } finally {
1443- sessionSpan .end ();
14441444 }
14451445 }
14461446
@@ -1467,12 +1467,12 @@ public Blob moveBlob(MoveBlobRequest request) {
14671467 public ApiFuture <BlobReadSession > blobReadSession (BlobId id , BlobSourceOption ... options ) {
14681468 Span blobReadSessionSpan =
14691469 tracer
1470- .spanBuilder ("blobReadSession" )
1470+ .spanBuilder (BLOB_READ_SESSION )
14711471 .setAttribute ("gsutil.uri" , id .toGsUtilUriWithGeneration ())
14721472 .startSpan ();
14731473 try (Scope ignore1 = blobReadSessionSpan .makeCurrent ()) {
14741474 Context blobReadSessionContext = Context .current ();
1475- Span ready = tracer .spanBuilder ("blobReadSession /ready" ).startSpan ();
1475+ Span ready = tracer .spanBuilder (BLOB_READ_SESSION + " /ready" ).startSpan ();
14761476 ApiFuture <BlobReadSession > blobReadSessionApiFuture = delegate .blobReadSession (id , options );
14771477 ApiFuture <BlobReadSession > futureDecorated =
14781478 ApiFutures .transform (
@@ -1561,7 +1561,7 @@ static UnaryOperator<RetryContext> retryContextDecorator(OpenTelemetry otel) {
15611561 return String .format (Locale .US , "gs://%s/" , bucket );
15621562 }
15631563
1564- private static final class TracerDecorator implements Tracer {
1564+ public static final class TracerDecorator implements Tracer {
15651565 @ Nullable private final Context parentContextOverride ;
15661566 private final Tracer delegate ;
15671567 private final Attributes baseAttributes ;
@@ -1578,7 +1578,7 @@ private TracerDecorator(
15781578 this .spanNamePrefix = spanNamePrefix ;
15791579 }
15801580
1581- private static TracerDecorator decorate (
1581+ public static TracerDecorator decorate (
15821582 @ Nullable Context parentContextOverride ,
15831583 OpenTelemetry otel ,
15841584 Attributes baseAttributes ,
@@ -1608,13 +1608,16 @@ static final class OtelDecoratedReadChannel implements ReadChannel {
16081608 @ VisibleForTesting final ReadChannel reader ;
16091609 private final Span span ;
16101610
1611+ private volatile Scope scope ;
1612+
16111613 private OtelDecoratedReadChannel (ReadChannel reader , Span span ) {
16121614 this .reader = reader ;
16131615 this .span = span ;
16141616 }
16151617
16161618 @ Override
16171619 public void seek (long position ) throws IOException {
1620+ clearScope ();
16181621 reader .seek (position );
16191622 }
16201623
@@ -1630,6 +1633,7 @@ public RestorableState<ReadChannel> capture() {
16301633
16311634 @ Override
16321635 public ReadChannel limit (long limit ) {
1636+ clearScope ();
16331637 return reader .limit (limit );
16341638 }
16351639
@@ -1640,6 +1644,7 @@ public long limit() {
16401644
16411645 @ Override
16421646 public int read (ByteBuffer dst ) throws IOException {
1647+ setScope ();
16431648 return reader .read (dst );
16441649 }
16451650
@@ -1650,21 +1655,38 @@ public boolean isOpen() {
16501655
16511656 @ Override
16521657 public void close () {
1658+ setScope ();
16531659 try {
16541660 reader .close ();
16551661 } finally {
16561662 span .end ();
1663+ clearScope ();
1664+ }
1665+ }
1666+
1667+ private void clearScope () {
1668+ try (Scope ignore = scope ) {
1669+ scope = null ;
1670+ }
1671+ }
1672+
1673+ public void setScope () {
1674+ if (scope != null ) {
1675+ clearScope ();
16571676 }
1677+ scope = span .makeCurrent ();
16581678 }
16591679 }
16601680
16611681 private final class OtelDecoratedBlobWriteSession implements BlobWriteSession {
16621682
16631683 private final BlobWriteSession delegate ;
1684+ private final Span sessionSpan ;
16641685 private final Tracer tracer ;
16651686
1666- public OtelDecoratedBlobWriteSession (BlobWriteSession delegate ) {
1687+ public OtelDecoratedBlobWriteSession (BlobWriteSession delegate , Span sessionSpan ) {
16671688 this .delegate = delegate ;
1689+ this .sessionSpan = sessionSpan ;
16681690 this .tracer =
16691691 TracerDecorator .decorate (
16701692 Context .current (),
@@ -1696,13 +1718,16 @@ private class OtelDecoratingWritableByteChannel implements WritableByteChannel {
16961718 private final WritableByteChannel delegate ;
16971719 private final Span openSpan ;
16981720
1721+ private Scope scope ;
1722+
16991723 private OtelDecoratingWritableByteChannel (WritableByteChannel delegate , Span openSpan ) {
17001724 this .delegate = delegate ;
17011725 this .openSpan = openSpan ;
17021726 }
17031727
17041728 @ Override
17051729 public int write (ByteBuffer src ) throws IOException {
1730+ setScope ();
17061731 return delegate .write (src );
17071732 }
17081733
@@ -1713,16 +1738,34 @@ public boolean isOpen() {
17131738
17141739 @ Override
17151740 public void close () throws IOException {
1741+ setScope ();
17161742 try {
17171743 delegate .close ();
17181744 } catch (IOException | RuntimeException e ) {
17191745 openSpan .recordException (e );
17201746 openSpan .setStatus (StatusCode .ERROR , e .getClass ().getSimpleName ());
1747+ sessionSpan .recordException (e );
1748+ sessionSpan .setStatus (StatusCode .ERROR , e .getClass ().getSimpleName ());
17211749 throw e ;
17221750 } finally {
17231751 openSpan .end ();
1752+ sessionSpan .end ();
1753+ clearScope ();
1754+ }
1755+ }
1756+
1757+ private void clearScope () {
1758+ try (Scope ignore = scope ) {
1759+ scope = null ;
17241760 }
17251761 }
1762+
1763+ public void setScope () {
1764+ if (scope != null ) {
1765+ clearScope ();
1766+ }
1767+ scope = openSpan .makeCurrent ();
1768+ }
17261769 }
17271770 }
17281771
@@ -1731,6 +1774,8 @@ static final class OtelDecoratedWriteChannel implements WriteChannel {
17311774 @ VisibleForTesting final WriteChannel delegate ;
17321775 private final Span openSpan ;
17331776
1777+ private Scope scope ;
1778+
17341779 private OtelDecoratedWriteChannel (WriteChannel delegate , Span openSpan ) {
17351780 this .delegate = delegate ;
17361781 this .openSpan = openSpan ;
@@ -1748,6 +1793,7 @@ public RestorableState<WriteChannel> capture() {
17481793
17491794 @ Override
17501795 public int write (ByteBuffer src ) throws IOException {
1796+ setScope ();
17511797 return delegate .write (src );
17521798 }
17531799
@@ -1758,6 +1804,7 @@ public boolean isOpen() {
17581804
17591805 @ Override
17601806 public void close () throws IOException {
1807+ setScope ();
17611808 try {
17621809 delegate .close ();
17631810 } catch (IOException | RuntimeException e ) {
@@ -1766,7 +1813,21 @@ public void close() throws IOException {
17661813 throw e ;
17671814 } finally {
17681815 openSpan .end ();
1816+ clearScope ();
1817+ }
1818+ }
1819+
1820+ private void clearScope () {
1821+ try (Scope ignore = scope ) {
1822+ scope = null ;
1823+ }
1824+ }
1825+
1826+ public void setScope () {
1827+ if (scope != null ) {
1828+ clearScope ();
17691829 }
1830+ scope = openSpan .makeCurrent ();
17701831 }
17711832 }
17721833
@@ -1962,7 +2023,7 @@ public BlobInfo getBlobInfo() {
19622023 public <Projection > Projection readAs (ReadProjectionConfig <Projection > config ) {
19632024 Span readRangeSpan =
19642025 tracer
1965- .spanBuilder (" readAs" )
2026+ .spanBuilder (BLOB_READ_SESSION + "/ readAs" )
19662027 .setAttribute ("gsutil.uri" , id .toGsUtilUriWithGeneration ())
19672028 .setParent (blobReadSessionContext )
19682029 .startSpan ();
@@ -2145,6 +2206,8 @@ private final class OtelDecoratingAppendableUploadWriteableByteChannel
21452206 private final AppendableUploadWriteableByteChannel delegate ;
21462207 private final Span openSpan ;
21472208
2209+ private volatile Scope scope ;
2210+
21482211 private OtelDecoratingAppendableUploadWriteableByteChannel (
21492212 AppendableUploadWriteableByteChannel delegate , Span openSpan ) {
21502213 this .delegate = delegate ;
@@ -2165,6 +2228,7 @@ public void finalizeAndClose() throws IOException {
21652228 } finally {
21662229 openSpan .end ();
21672230 uploadSpan .end ();
2231+ clearScope ();
21682232 }
21692233 }
21702234
@@ -2182,12 +2246,14 @@ public void closeWithoutFinalizing() throws IOException {
21822246 } finally {
21832247 openSpan .end ();
21842248 uploadSpan .end ();
2249+ clearScope ();
21852250 }
21862251 }
21872252
21882253 @ Override
21892254 @ BetaApi
21902255 public void close () throws IOException {
2256+ setScope ();
21912257 try {
21922258 delegate .close ();
21932259 } catch (IOException | RuntimeException e ) {
@@ -2199,18 +2265,33 @@ public void close() throws IOException {
21992265 } finally {
22002266 openSpan .end ();
22012267 uploadSpan .end ();
2268+ clearScope ();
22022269 }
22032270 }
22042271
22052272 @ Override
22062273 public int write (ByteBuffer src ) throws IOException {
2274+ setScope ();
22072275 return delegate .write (src );
22082276 }
22092277
22102278 @ Override
22112279 public boolean isOpen () {
22122280 return delegate .isOpen ();
22132281 }
2282+
2283+ private void clearScope () {
2284+ try (Scope ignore = scope ) {
2285+ scope = null ;
2286+ }
2287+ }
2288+
2289+ public void setScope () {
2290+ if (scope != null ) {
2291+ clearScope ();
2292+ }
2293+ scope = openSpan .makeCurrent ();
2294+ }
22142295 }
22152296 }
22162297}
0 commit comments