Skip to content

Commit e91cc07

Browse files
authored
Enable collection of more metrics (esp. I/O level) via Honeycomb (#1492)
This required refactoring the Galley timing function providers, using a new patch of Galley that attempts to generalize the metrics interface, at least for I/O operations. It also involved creating three new interceptors, which would handle methods that are designed to wrap arbitrary pieces of code in metrics.
1 parent e3953f6 commit e91cc07

File tree

35 files changed

+580
-83
lines changed

35 files changed

+580
-83
lines changed

addons/folo/jaxrs/src/main/java/org/commonjava/indy/folo/bind/jaxrs/FoloMavenContentAccessResource.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@
2626
import org.commonjava.indy.core.bind.jaxrs.ContentAccessHandler;
2727
import org.commonjava.indy.core.bind.jaxrs.util.RequestUtils;
2828
import org.commonjava.indy.folo.model.TrackingKey;
29+
import org.commonjava.indy.metrics.RequestContextHelper;
2930
import org.commonjava.indy.model.core.AccessChannel;
3031
import org.commonjava.maven.galley.event.EventMetadata;
3132
import org.slf4j.Logger;
3233
import org.slf4j.LoggerFactory;
33-
import org.slf4j.MDC;
34+
import org.commonjava.indy.metrics.RequestContextHelper;
3435

3536
import javax.inject.Inject;
3637
import javax.servlet.http.HttpServletRequest;
@@ -124,7 +125,7 @@ public Response doHead( @ApiParam( "User-assigned tracking session key" ) @PathP
124125
EventMetadata metadata =
125126
new EventMetadata().set( TRACKING_KEY, tk ).set( ACCESS_CHANNEL, AccessChannel.NATIVE );
126127

127-
MDC.put( CONTENT_TRACKING_ID, id );
128+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
128129

129130
return handler.doHead( PKG_TYPE_MAVEN, type, name, path, cacheOnly, baseUri, request, metadata );
130131
}
@@ -147,7 +148,7 @@ public Response doGet( @ApiParam( "User-assigned tracking session key" ) @PathPa
147148
EventMetadata metadata =
148149
new EventMetadata().set( TRACKING_KEY, tk ).set( ACCESS_CHANNEL, AccessChannel.NATIVE );
149150

150-
MDC.put( CONTENT_TRACKING_ID, id );
151+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
151152

152153
return handler.doGet( PKG_TYPE_MAVEN, type, name, path, baseUri, request, metadata );
153154
}

addons/folo/jaxrs/src/main/java/org/commonjava/indy/folo/bind/jaxrs/FoloNPMContentAccessResource.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@
2525
import org.commonjava.indy.bind.jaxrs.util.REST;
2626
import org.commonjava.indy.core.bind.jaxrs.util.RequestUtils;
2727
import org.commonjava.indy.folo.model.TrackingKey;
28+
import org.commonjava.indy.metrics.RequestContextHelper;
2829
import org.commonjava.indy.model.core.AccessChannel;
2930
import org.commonjava.indy.pkg.npm.inject.NPMContentHandler;
3031
import org.commonjava.indy.pkg.npm.jaxrs.NPMContentAccessHandler;
3132
import org.commonjava.maven.galley.event.EventMetadata;
3233
import org.slf4j.Logger;
3334
import org.slf4j.LoggerFactory;
34-
import org.slf4j.MDC;
35+
import org.commonjava.indy.metrics.RequestContextHelper;
3536

3637
import javax.inject.Inject;
3738
import javax.servlet.http.HttpServletRequest;
@@ -153,7 +154,7 @@ public Response doHead( @ApiParam( "User-assigned tracking session key" ) @PathP
153154
EventMetadata metadata = new EventMetadata().set( TRACKING_KEY, tk )
154155
.set( ACCESS_CHANNEL, AccessChannel.NATIVE );
155156

156-
MDC.put( CONTENT_TRACKING_ID, id );
157+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
157158

158159
return handler.doHead( NPM_PKG_KEY, type, name, packageName, cacheOnly, baseUri, request, metadata );
159160
}
@@ -176,7 +177,7 @@ public Response doHead( @ApiParam( "User-assigned tracking session key" ) @PathP
176177
EventMetadata metadata =
177178
new EventMetadata().set( TRACKING_KEY, tk ).set( ACCESS_CHANNEL, AccessChannel.NATIVE );
178179

179-
MDC.put( CONTENT_TRACKING_ID, id );
180+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
180181

181182
final String baseUri = getBasePath( uriInfo, id );
182183
final String path = Paths.get( packageName, versionTarball ).toString();
@@ -203,7 +204,7 @@ public Response doGet( @ApiParam( "User-assigned tracking session key" ) @PathPa
203204
EventMetadata metadata = new EventMetadata().set( TRACKING_KEY, tk )
204205
.set( ACCESS_CHANNEL, AccessChannel.NATIVE );
205206

206-
MDC.put( CONTENT_TRACKING_ID, id );
207+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
207208

208209
return handler.doGet( NPM_PKG_KEY, type, name, packageName, baseUri, request, metadata );
209210
}
@@ -225,7 +226,7 @@ public Response doGet( @ApiParam( "User-assigned tracking session key" ) @PathPa
225226
final TrackingKey tk = new TrackingKey( id );
226227
EventMetadata metadata =
227228
new EventMetadata().set( TRACKING_KEY, tk ).set( ACCESS_CHANNEL, AccessChannel.NATIVE );
228-
MDC.put( CONTENT_TRACKING_ID, id );
229+
RequestContextHelper.setContext( CONTENT_TRACKING_ID, id );
229230

230231
final String path = Paths.get( packageName, versionTarball ).toString();
231232
final String baseUri = getBasePath( uriInfo, id );

addons/httprox/common/src/main/java/org/commonjava/indy/httprox/handler/ProxyAcceptHandler.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.commonjava.maven.galley.spi.cache.CacheProvider;
3232
import org.slf4j.Logger;
3333
import org.slf4j.LoggerFactory;
34-
import org.slf4j.MDC;
34+
import org.commonjava.indy.metrics.RequestContextHelper;
3535
import org.xnio.ChannelListener;
3636
import org.xnio.StreamConnection;
3737
import org.xnio.channels.AcceptingChannel;
@@ -135,7 +135,7 @@ public ProxyRepositoryCreator createRepoCreator()
135135
public void handleEvent( AcceptingChannel<StreamConnection> channel )
136136
{
137137
long start = System.nanoTime();
138-
MDC.put( RequestContextHelper.ACCESS_CHANNEL, AccessChannel.GENERIC_PROXY.toString() );
138+
RequestContextHelper.setContext( RequestContextHelper.ACCESS_CHANNEL, AccessChannel.GENERIC_PROXY.toString() );
139139
setContext( PACKAGE_TYPE, PKG_TYPE_GENERIC_HTTP );
140140

141141
final Logger logger = LoggerFactory.getLogger( getClass() );
@@ -157,10 +157,10 @@ public void handleEvent( AcceptingChannel<StreamConnection> channel )
157157
return;
158158
}
159159

160-
MDC.put( REQUEST_PHASE, REQUEST_PHASE_START );
160+
RequestContextHelper.setContext( REQUEST_PHASE, REQUEST_PHASE_START );
161161
LoggerFactory.getLogger( PROXY_METRIC_LOGGER )
162162
.info( "START HTTProx request (from: {})", accepted.getPeerAddress() );
163-
MDC.remove( REQUEST_PHASE );
163+
RequestContextHelper.clearContext( REQUEST_PHASE );
164164

165165
logger.debug( "accepted {}", accepted.getPeerAddress() );
166166

addons/httprox/common/src/main/java/org/commonjava/indy/httprox/handler/ProxyResponseWriter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import org.commonjava.maven.galley.spi.cache.CacheProvider;
4646
import org.slf4j.Logger;
4747
import org.slf4j.LoggerFactory;
48-
import org.slf4j.MDC;
48+
import org.commonjava.indy.metrics.RequestContextHelper;
4949
import org.xnio.ChannelListener;
5050
import org.xnio.StreamConnection;
5151
import org.xnio.conduits.ConduitStreamSinkChannel;
@@ -278,7 +278,7 @@ private void doHandleEvent( final ConduitStreamSinkChannel sinkChannel )
278278
if ( trackingKey != null )
279279
{
280280
trackingId = trackingKey.getId();
281-
MDC.put( RequestContextHelper.CONTENT_TRACKING_ID, trackingId );
281+
RequestContextHelper.setContext( RequestContextHelper.CONTENT_TRACKING_ID, trackingId );
282282
}
283283

284284
String authCacheKey = generateAuthCacheKey( proxyUserPass );

addons/httprox/common/src/main/java/org/commonjava/indy/httprox/util/ProxyMeter.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import org.commonjava.indy.sli.metrics.GoldenSignalsMetricSet;
1919
import org.slf4j.Logger;
20-
import org.slf4j.MDC;
20+
import org.commonjava.indy.metrics.RequestContextHelper;
2121

2222
import java.net.SocketAddress;
2323

@@ -73,7 +73,7 @@ public void reportResponseSummary()
7373

7474
long latency = System.nanoTime() - startNanos;
7575

76-
MDC.put( REQUEST_LATENCY_NS, String.valueOf( latency ) );
76+
RequestContextHelper.setContext( REQUEST_LATENCY_NS, String.valueOf( latency ) );
7777
setContext( HTTP_METHOD, method );
7878

7979
// log SLI metrics
@@ -89,9 +89,9 @@ public void reportResponseSummary()
8989
} );
9090
}
9191

92-
MDC.put( REQUEST_PHASE, REQUEST_PHASE_END );
92+
RequestContextHelper.setContext( REQUEST_PHASE, REQUEST_PHASE_END );
9393
restLogger.info( "END {} (from: {})", requestLine, peerAddress );
94-
MDC.remove( REQUEST_PHASE );
94+
RequestContextHelper.clearContext( REQUEST_PHASE );
9595
}
9696
}
9797

addons/pkg-maven/common/src/main/java/org/commonjava/indy/pkg/maven/content/MavenContentsFilteringTransferDecorator.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ private String filterMetadata()
215215
return "";
216216
}
217217

218-
Timer.Context timer = metricsManager == null ? null : metricsManager.getTimer( TIMER ).time();
218+
Timer.Context timer = metricsManager == null ? null : metricsManager.startTimer( TIMER );
219219
try
220220
{
221221
// filter versions from GA metadata
@@ -321,7 +321,7 @@ private String filterMetadata()
321321
{
322322
if ( timer != null )
323323
{
324-
timer.stop();
324+
metricsManager.stopTimer( TIMER );
325325
}
326326
}
327327
}

addons/pkg-npm/common/src/main/java/org/commonjava/indy/pkg/npm/content/NPMPackageMaskingTransferDecorator.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public synchronized int read( byte[] b, int off, int len ) throws IOException
159159

160160
private void mask( String contextURL ) throws IOException
161161
{
162-
Timer.Context timer = metricsManager == null ? null : metricsManager.getTimer( TIMER ).time();
162+
Timer.Context timer = metricsManager == null ? null : metricsManager.startTimer( TIMER );
163163
try
164164
{
165165
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -183,7 +183,7 @@ private void mask( String contextURL ) throws IOException
183183
{
184184
if ( timer != null )
185185
{
186-
timer.stop();
186+
metricsManager.stopTimer( TIMER );
187187
}
188188
}
189189
}

addons/promote/common/src/main/java/org/commonjava/indy/promote/data/PromotionManager.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
import org.commonjava.maven.galley.spi.nfc.NotFoundCache;
5656
import org.slf4j.Logger;
5757
import org.slf4j.LoggerFactory;
58-
import org.slf4j.MDC;
58+
import org.commonjava.indy.metrics.RequestContextHelper;
5959

6060
import javax.enterprise.context.ApplicationScoped;
6161
import javax.enterprise.event.Event;
@@ -203,10 +203,10 @@ public PromotionManager( PromotionValidator validator, ContentManager contentMan
203203
public GroupPromoteResult promoteToGroup( GroupPromoteRequest request, String user, String baseUrl )
204204
throws PromotionException, IndyWorkflowException
205205
{
206-
MDC.put( PROMOTION_ID, request.getPromotionId() );
207-
MDC.put( PROMOTION_TYPE, GROUP_PROMOTION );
208-
MDC.put( PROMOTION_SOURCE, request.getSource().toString() );
209-
MDC.put( PROMOTION_TARGET, request.getTargetKey().toString() );
206+
RequestContextHelper.setContext( PROMOTION_ID, request.getPromotionId() );
207+
RequestContextHelper.setContext( PROMOTION_TYPE, GROUP_PROMOTION );
208+
RequestContextHelper.setContext( PROMOTION_SOURCE, request.getSource().toString() );
209+
RequestContextHelper.setContext( PROMOTION_TARGET, request.getTargetKey().toString() );
210210

211211
if ( !storeManager.hasArtifactStore( request.getSource() ) )
212212
{
@@ -515,10 +515,10 @@ private Future<GroupPromoteResult> submitGroupPromoteRequest( final GroupPromote
515515
public PathsPromoteResult promotePaths( final PathsPromoteRequest request, final String baseUrl )
516516
throws PromotionException, IndyWorkflowException
517517
{
518-
MDC.put( PROMOTION_ID, request.getPromotionId() );
519-
MDC.put( PROMOTION_TYPE, PATH_PROMOTION );
520-
MDC.put( PROMOTION_SOURCE, request.getSource().toString() );
521-
MDC.put( PROMOTION_TARGET, request.getTargetKey().toString() );
518+
RequestContextHelper.setContext( PROMOTION_ID, request.getPromotionId() );
519+
RequestContextHelper.setContext( PROMOTION_TYPE, PATH_PROMOTION );
520+
RequestContextHelper.setContext( PROMOTION_SOURCE, request.getSource().toString() );
521+
RequestContextHelper.setContext( PROMOTION_TARGET, request.getTargetKey().toString() );
522522

523523
Future<PathsPromoteResult> future = submitPathsPromoteRequest( request, baseUrl );
524524
if ( request.isAsync() )
@@ -858,7 +858,7 @@ private Callable<Set<PathTransferResult>> newPathPromotionsJob( final Collection
858858
PathTransferResult ret = doPathTransfer( transfer, tgt, request );
859859
results.add( ret );
860860
}
861-
MDC.put( PROMOTION_CONTENT_PATH, pathsForMDC.toString() );
861+
RequestContextHelper.setContext( PROMOTION_CONTENT_PATH, pathsForMDC.toString() );
862862
return results;
863863
};
864864
}

addons/promote/common/src/main/java/org/commonjava/indy/promote/validate/PromotionValidationTools.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.commonjava.maven.galley.transport.htcli.model.HttpExchangeMetadata;
5656
import org.slf4j.Logger;
5757
import org.slf4j.LoggerFactory;
58+
import org.commonjava.indy.metrics.RequestContextHelper;
5859
import org.slf4j.MDC;
5960

6061
import javax.inject.Inject;
@@ -633,8 +634,8 @@ private <T> void runParallelInBatchAndWait( Collection<Collection<T>> batches, C
633634
logger.trace( "The paralleled exe on batch {}", batch );
634635
batch.forEach( e -> {
635636
String depthStr = MDC.get( ITERATION_DEPTH );
636-
MDC.put( ITERATION_DEPTH, depthStr == null ? "0" : String.valueOf( Integer.parseInt( depthStr ) + 1 ) );
637-
MDC.put( ITERATION_ITEM, String.valueOf( e ) );
637+
RequestContextHelper.setContext( ITERATION_DEPTH, depthStr == null ? "0" : String.valueOf( Integer.parseInt( depthStr ) + 1 ) );
638+
RequestContextHelper.setContext( ITERATION_ITEM, String.valueOf( e ) );
638639
try
639640
{
640641
closure.call( e );
@@ -661,8 +662,8 @@ private <T> void runParallelAndWait( Collection<T> runCollection, Closure closur
661662
final CountDownLatch latch = new CountDownLatch( todo.size() );
662663
todo.forEach( e -> ruleParallelExecutor.execute( () -> {
663664
String depthStr = MDC.get( ITERATION_DEPTH );
664-
MDC.put( ITERATION_DEPTH, depthStr == null ? "0" : String.valueOf( Integer.parseInt( depthStr ) + 1 ) );
665-
MDC.put( ITERATION_ITEM, String.valueOf( e ) );
665+
RequestContextHelper.setContext( ITERATION_DEPTH, depthStr == null ? "0" : String.valueOf( Integer.parseInt( depthStr ) + 1 ) );
666+
RequestContextHelper.setContext( ITERATION_ITEM, String.valueOf( e ) );
666667

667668
try
668669
{

addons/promote/common/src/main/java/org/commonjava/indy/promote/validate/PromotionValidator.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.commonjava.maven.galley.model.Transfer;
4444
import org.slf4j.Logger;
4545
import org.slf4j.LoggerFactory;
46+
import org.commonjava.indy.metrics.RequestContextHelper;
4647
import org.slf4j.MDC;
4748

4849
import javax.inject.Inject;
@@ -145,7 +146,7 @@ public ValidationRequest validate( PromoteRequest request, ValidationResult resu
145146
if ( set != null )
146147
{
147148
result.setRuleSet( set.getName() );
148-
MDC.put( PROMOTION_VALIDATION_RULE_SET, set.getName() );
149+
RequestContextHelper.setContext( PROMOTION_VALIDATION_RULE_SET, set.getName() );
149150

150151
logger.debug( "Running validation rule-set for promotion: {}", set.getName() );
151152

@@ -163,7 +164,7 @@ public ValidationRequest validate( PromoteRequest request, ValidationResult resu
163164
for ( String ruleRef : ruleNames )
164165
{
165166
svc.submit( () -> {
166-
MDC.put( PROMOTION_VALIDATION_RULE, ruleRef );
167+
RequestContextHelper.setContext( PROMOTION_VALIDATION_RULE, ruleRef );
167168
Exception err = null;
168169
try
169170
{
@@ -175,7 +176,7 @@ public ValidationRequest validate( PromoteRequest request, ValidationResult resu
175176
}
176177
finally
177178
{
178-
MDC.remove( PROMOTION_VALIDATION_RULE );
179+
RequestContextHelper.clearContext( PROMOTION_VALIDATION_RULE );
179180
}
180181

181182
return err;

addons/sli/jaxrs/src/main/java/org/commonjava/indy/sli/jaxrs/GoldenSignalsFilter.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.commonjava.maven.galley.spi.io.SpecialPathManager;
3232
import org.slf4j.Logger;
3333
import org.slf4j.LoggerFactory;
34-
import org.slf4j.MDC;
34+
import org.commonjava.indy.metrics.RequestContextHelper;
3535

3636
import javax.enterprise.context.ApplicationScoped;
3737
import javax.inject.Inject;
@@ -53,6 +53,8 @@
5353
import static java.util.Collections.emptyList;
5454
import static java.util.Collections.singletonList;
5555
import static org.apache.commons.lang3.StringUtils.join;
56+
import static org.commonjava.indy.IndyContentConstants.NANOS_PER_MILLISECOND;
57+
import static org.commonjava.indy.metrics.RequestContextHelper.REQUEST_LATENCY_MILLIS;
5658
import static org.commonjava.indy.metrics.RequestContextHelper.REQUEST_LATENCY_NS;
5759
import static org.commonjava.indy.pkg.PackageTypeConstants.PKG_TYPE_MAVEN;
5860
import static org.commonjava.indy.pkg.PackageTypeConstants.PKG_TYPE_NPM;
@@ -141,7 +143,8 @@ public void doFilter( final ServletRequest servletRequest, final ServletResponse
141143
// latency.
142144
long end = RequestContextHelper.getRequestEndNanos() - RequestContextHelper.getRawIoWriteNanos();
143145

144-
MDC.put( REQUEST_LATENCY_NS, String.valueOf( end - start ) );
146+
RequestContextHelper.setContext( REQUEST_LATENCY_NS, String.valueOf( end - start ) );
147+
RequestContextHelper.setContext( REQUEST_LATENCY_MILLIS, (end-start) / NANOS_PER_MILLISECOND );
145148

146149
Set<String> functions = new HashSet<>( getFunctions( req.getPathInfo(), req.getMethod() ) );
147150
boolean error = resp.getStatus() > 499;

api/src/main/java/org/commonjava/indy/metrics/RequestContextHelper.java

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ public static long getRawIoWriteNanos()
120120
@MDC
121121
public static final String REQUEST_LATENCY_NS = "request-latency-ns";
122122

123+
@Thread
124+
public static final String REQUEST_LATENCY_MILLIS = "request-latency";
125+
123126
@MDC
124127
public static final String REQUEST_PHASE = "request-phase";
125128

bindings/jaxrs/src/main/java/org/commonjava/indy/core/bind/jaxrs/ContentAccessHandler.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@
3131
import org.commonjava.indy.model.core.PackageTypes;
3232
import org.commonjava.indy.model.core.StoreKey;
3333
import org.commonjava.indy.model.core.StoreType;
34-
import org.commonjava.indy.util.*;
34+
import org.commonjava.indy.util.AcceptInfo;
35+
import org.commonjava.indy.util.ApplicationContent;
36+
import org.commonjava.indy.util.ApplicationHeader;
37+
import org.commonjava.indy.util.ApplicationStatus;
38+
import org.commonjava.indy.util.LocationUtils;
39+
import org.commonjava.indy.util.UriFormatter;
3540
import org.commonjava.maven.galley.event.EventMetadata;
3641
import org.commonjava.maven.galley.io.checksum.ContentDigest;
3742
import org.commonjava.maven.galley.model.SpecialPathInfo;
@@ -56,13 +61,13 @@
5661
import java.util.function.Consumer;
5762
import java.util.function.Supplier;
5863

64+
import static org.commonjava.indy.core.ctl.ContentController.LISTING_HTML_FILE;
5965
import static org.commonjava.indy.metrics.RequestContextHelper.CONTENT_ENTRY_POINT;
6066
import static org.commonjava.indy.metrics.RequestContextHelper.HTTP_STATUS;
6167
import static org.commonjava.indy.metrics.RequestContextHelper.METADATA_CONTENT;
6268
import static org.commonjava.indy.metrics.RequestContextHelper.PACKAGE_TYPE;
6369
import static org.commonjava.indy.metrics.RequestContextHelper.PATH;
6470
import static org.commonjava.indy.metrics.RequestContextHelper.setContext;
65-
import static org.commonjava.indy.core.ctl.ContentController.LISTING_HTML_FILE;
6671
import static org.commonjava.indy.pkg.npm.model.NPMPackageTypeDescriptor.NPM_PKG_KEY;
6772

6873
@ApplicationScoped

embedder/src/main/resources/META-INF/beans.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<interceptors>
3131
<class>org.commonjava.indy.bind.jaxrs.util.RestInterceptor</class>
3232
<class>org.commonjava.indy.metrics.jaxrs.interceptor.MetricsInterceptor</class>
33-
<class>org.commonjava.indy.subsys.honeycomb.interceptor.HoneycombInterceptor</class>
33+
<class>org.commonjava.indy.subsys.honeycomb.interceptor.HoneycombMeasureInterceptor</class>
3434
</interceptors>
3535

3636
<!-- NOTE: In the decorators below, the FIRST listed will be invoked FIRST (outer-most in the stack) -->

0 commit comments

Comments
 (0)