From 758f0df1b04846b9ac930b24174d6ddc5bb71193 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Thu, 4 Apr 2024 12:29:26 -0500 Subject: [PATCH] initial checkin --- .gitignore | 5 ++ netflix-zuul-core-1.x/build.gradle | 30 +++++++++ .../com/netflix/zuul/FilterProcessor.java | 24 +++++++ .../java/com/netflix/zuul/IZuulFilter.java | 20 ++++++ .../java/com/netflix/zuul/ZuulFilter.java | 32 +++++++++ netflix-zuul-core-2.1.6/build.gradle | 28 ++++++++ .../HttpClientLifecycleChannelHandler.java | 40 +++++++++++ ...fecycleChannelHandler_instrumentation.java | 49 ++++++++++++++ .../HttpServerLifecycleChannelHandler.java | 38 +++++++++++ .../netflix/zuul/RequestCompleteHandler.java | 27 ++++++++ .../netflix/zuul/filters/SyncZuulFilter.java | 24 +++++++ .../filters/ZuulFilter_instrumentation.java | 35 ++++++++++ .../netty/filter/BaseZuulFilterRunner.java | 39 +++++++++++ .../zuul/netty/filter/FilterRunner.java | 27 ++++++++ .../netty/filter/ZuulFilterChainHandler.java | 29 ++++++++ .../PassportStateHttpClientHandler.java | 36 ++++++++++ .../PassportStateHttpServerHandler.java | 45 +++++++++++++ .../netty/server/ClientRequestReceiver.java | 36 ++++++++++ .../netty/server/ClientResponseWriter.java | 28 ++++++++ .../netty/server/OriginResponseReceiver.java | 37 ++++++++++ .../netflix_zuul/NettyRequestHeaders.java | 67 +++++++++++++++++++ .../labs/netflix_zuul/Utils.java | 22 ++++++ .../labs/netflix_zuul/ZuulDispatcher.java | 61 +++++++++++++++++ ...ChannelHandlerContext_Instrumentation.java | 11 +++ ...ChannelInboundHandler_Instrumentation.java | 20 ++++++ .../ChannelPipeline_Instrumentation.java | 15 +++++ netflix-zuul-core-2.1/build.gradle | 28 ++++++++ .../HttpClientLifecycleChannelHandler.java | 40 +++++++++++ ...fecycleChannelHandler_instrumentation.java | 49 ++++++++++++++ .../HttpServerLifecycleChannelHandler.java | 38 +++++++++++ .../netflix/zuul/RequestCompleteHandler.java | 27 ++++++++ .../netflix/zuul/filters/SyncZuulFilter.java | 24 +++++++ .../filters/ZuulFilter_instrumentation.java | 35 ++++++++++ .../netty/filter/BaseZuulFilterRunner.java | 39 +++++++++++ .../zuul/netty/filter/FilterRunner.java | 27 ++++++++ .../netty/filter/ZuulFilterChainHandler.java | 29 ++++++++ .../PassportStateHttpClientHandler.java | 36 ++++++++++ .../PassportStateHttpServerHandler.java | 45 +++++++++++++ .../netty/server/ClientRequestReceiver.java | 36 ++++++++++ .../netty/server/ClientResponseWriter.java | 28 ++++++++ .../netty/server/OriginResponseReceiver.java | 37 ++++++++++ .../netflix_zuul/NettyRequestHeaders.java | 67 +++++++++++++++++++ .../labs/netflix_zuul/Utils.java | 22 ++++++ .../labs/netflix_zuul/ZuulDispatcher.java | 61 +++++++++++++++++ ...ChannelHandlerContext_Instrumentation.java | 11 +++ ...ChannelInboundHandler_Instrumentation.java | 20 ++++++ .../ChannelPipeline_Instrumentation.java | 15 +++++ settings.gradle | 4 ++ spring-zuul/build.gradle | 31 +++++++++ .../netflix/zuul/filters/RouteLocator.java | 41 ++++++++++++ .../netflix/zuul/web/ZuulController.java | 33 +++++++++ 51 files changed, 1648 insertions(+) create mode 100644 netflix-zuul-core-1.x/build.gradle create mode 100644 netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/FilterProcessor.java create mode 100644 netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/IZuulFilter.java create mode 100644 netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/ZuulFilter.java create mode 100644 netflix-zuul-core-2.1.6/build.gradle create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/RequestCompleteHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java create mode 100644 netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java create mode 100644 netflix-zuul-core-2.1/build.gradle create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/RequestCompleteHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java create mode 100644 netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java create mode 100644 netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java create mode 100644 netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java create mode 100644 netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java create mode 100644 spring-zuul/build.gradle create mode 100644 spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/RouteLocator.java create mode 100644 spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/web/ZuulController.java diff --git a/.gitignore b/.gitignore index 3589ff9..714be6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .java-version .git .github +.classpath +.project +.settings +build +bin diff --git a/netflix-zuul-core-1.x/build.gradle b/netflix-zuul-core-1.x/build.gradle new file mode 100644 index 0000000..312756a --- /dev/null +++ b/netflix-zuul-core-1.x/build.gradle @@ -0,0 +1,30 @@ + +// Build.gradle generated for instrumentation module netflix-zuul-core-1.x + +apply plugin: 'java' + +dependencies { + implementation group: 'com.netflix.zuul', name: 'zuul-core', version: '1.2.0' + compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' + + + // New Relic Java Agent dependencies + implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0' + implementation 'com.newrelic.agent.java:newrelic-api:6.4.0' + implementation fileTree(include: ['*.jar'], dir: '../libs') + implementation fileTree(include: ['*.jar'], dir: '../test-lib') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.netflix-zuul-core-1.x' + attributes 'Implementation-Vendor': 'New Relic' + attributes 'Implementation-Vendor-Id': 'com.newrelic' + attributes 'Implementation-Version': 1.0 + } +} + +verifyInstrumentation { + passes 'com.netflix.zuul:zuul-core:[1.2.0,2.1.1)' + excludeRegex '.*rc.[1-9]' +} \ No newline at end of file diff --git a/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/FilterProcessor.java b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/FilterProcessor.java new file mode 100644 index 0000000..01e699a --- /dev/null +++ b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/FilterProcessor.java @@ -0,0 +1,24 @@ +package com.netflix.zuul; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave +public abstract class FilterProcessor { + + @Trace + public void preRoute() { + Weaver.callOriginal(); + } + + @Trace + public void route() { + Weaver.callOriginal(); + } + + @Trace + public void postRoute() { + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/IZuulFilter.java b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/IZuulFilter.java new file mode 100644 index 0000000..7d3b1bb --- /dev/null +++ b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/IZuulFilter.java @@ -0,0 +1,20 @@ +package com.netflix.zuul; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface) +public abstract class IZuulFilter { + + @Trace + public Object run() { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Custom","Zuul","ZuulFilter",getClass().getSimpleName(),"run"); + return Weaver.callOriginal(); + } + +} diff --git a/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/ZuulFilter.java b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/ZuulFilter.java new file mode 100644 index 0000000..44f0f20 --- /dev/null +++ b/netflix-zuul-core-1.x/src/main/java/com/netflix/zuul/ZuulFilter.java @@ -0,0 +1,32 @@ +package com.netflix.zuul; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type=MatchType.BaseClass) +public abstract class ZuulFilter { + + public abstract String filterType(); + + @Trace + public ZuulFilterResult runFilter() { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Custom","Zuul","ZuulFilter",getClass().getSimpleName(),"runFilter"); + traced.addCustomAttribute("FilterType", filterType()); + ZuulFilterResult fResult = Weaver.callOriginal(); + String status = fResult != null ? fResult.getStatus() != null ? fResult.getStatus().name() : null : null; + if(status != null) { + traced.addCustomAttribute("FilterResult",status); + } + Throwable t = fResult != null ? fResult.getException() : null; + if(t != null) { + NewRelic.noticeError(t); + } + return fResult; + } + +} diff --git a/netflix-zuul-core-2.1.6/build.gradle b/netflix-zuul-core-2.1.6/build.gradle new file mode 100644 index 0000000..199de30 --- /dev/null +++ b/netflix-zuul-core-2.1.6/build.gradle @@ -0,0 +1,28 @@ + +// Build.gradle generated for instrumentation module netflix-zuul-core-2.1 + +apply plugin: 'java' + +dependencies { + implementation 'com.netflix.zuul:zuul-core:2.1.6' + implementation group: 'io.netty', name: 'netty-tcnative-boringssl-static', version: '2.0.7.Final' + + // New Relic Java Agent dependencies + implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0' + implementation 'com.newrelic.agent.java:newrelic-api:6.4.0' + implementation fileTree(include: ['*.jar'], dir: '../libs') + implementation fileTree(include: ['*.jar'], dir: '../test-lib') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.netflix-zuul-core-2.1.6' + attributes 'Implementation-Vendor': 'New Relic' + attributes 'Implementation-Vendor-Id': 'com.newrelic' + attributes 'Implementation-Version': 1.0 + } +} + +verifyInstrumentation { + passes 'com.netflix.zuul:zuul-core:[2.1.6,)' +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java new file mode 100644 index 0000000..5a1dec5 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java @@ -0,0 +1,40 @@ +package com.netflix.netty.common; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class HttpClientLifecycleChannelHandler { + + @Weave + private static class HttpClientLifecycleInboundChannelHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + + } + + @Weave + private static class HttpClientLifecycleOutboundChannelHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + + } + + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java new file mode 100644 index 0000000..c5ac318 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java @@ -0,0 +1,49 @@ +package com.netflix.netty.common; + +import com.netflix.netty.common.HttpLifecycleChannelHandler.CompleteReason; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.instrumentation.labs.netflix_zuul.NettyRequestHeaders; +import com.newrelic.instrumentation.labs.netflix_zuul.ZuulDispatcher; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; + +@Weave(originalName = "com.netflix.netty.common.HttpLifecycleChannelHandler") +public abstract class HttpLifecycleChannelHandler_instrumentation { + + + protected static boolean fireCompleteEventIfNotAlready(ChannelHandlerContext_Instrumentation ctx, CompleteReason reason) { + boolean b = Weaver.callOriginal(); + if(b) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.expire(); + ctx.pipeline().zuul_token = null; + } + } + + return b; + } + + protected static boolean fireStartEvent(ChannelHandlerContext_Instrumentation ctx, HttpRequest request) { + boolean b = Weaver.callOriginal(); + if(b) { + ZuulDispatcher.get().channelRead(ctx, request); + NettyRequestHeaders headers = new NettyRequestHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + if(ctx.pipeline().zuul_token == null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if(t != null && t.isActive()) { + ctx.pipeline().zuul_token= t; + } else if(t != null) { + t.expire(); + t = null; + } + } + } + + return b; + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java new file mode 100644 index 0000000..7ca8b52 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java @@ -0,0 +1,38 @@ +package com.netflix.netty.common; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class HttpServerLifecycleChannelHandler { + + @Weave + public static class HttpServerLifecycleInboundChannelHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } + + @Weave + public static class HttpServerLifecycleOutboundChannelHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/RequestCompleteHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/RequestCompleteHandler.java new file mode 100644 index 0000000..73f8144 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/RequestCompleteHandler.java @@ -0,0 +1,27 @@ +package com.netflix.zuul; + +import java.util.HashMap; + +import com.netflix.zuul.message.http.HttpRequestInfo; +import com.netflix.zuul.message.http.HttpResponseMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.instrumentation.labs.netflix_zuul.Utils; + +@Weave(type = MatchType.Interface) +public class RequestCompleteHandler { + + @Trace + public void handle(HttpRequestInfo inboundRequest, HttpResponseMessage response) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + HashMap attributes = new HashMap<>(); + Utils.addRequestInfo(attributes, inboundRequest); + traced.addCustomAttribute("In", inboundRequest.getMethod()); + traced.setMetricName("Custom","Netflix","Zuul","RequestCompleteHandler",getClass().getSimpleName(),"handle"); + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java new file mode 100644 index 0000000..a81e4d2 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java @@ -0,0 +1,24 @@ +package com.netflix.zuul.filters; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface) +public abstract class SyncZuulFilter implements ZuulFilter { + + @Trace + public O apply(I input) { + String filterName = filterName(); + if(filterName != null && !filterName.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","SyncZuulFilter",filterName,"apply"); + } else { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","SyncZuulFilter",getClass().getSimpleName(),"apply"); + } + return Weaver.callOriginal(); + } + +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java new file mode 100644 index 0000000..3ae0adf --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java @@ -0,0 +1,35 @@ +package com.netflix.zuul.filters; + +import java.util.Hashtable; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import rx.Observable; + +@Weave(type=MatchType.Interface, originalName = "com.netflix.zuul.filters.ZuulFilter") +public abstract class ZuulFilter_instrumentation { + + public abstract FilterSyncType getSyncType(); + public abstract String filterName(); + public abstract FilterType filterType(); + + @Trace + public Observable applyAsync(I input) { + String filterName = filterName(); + if(filterName != null && !filterName.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","ZuulFilter",filterName,"applyAsync"); + } else { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","ZuulFilter",getClass().getSimpleName(),"applyAsync"); + } + Hashtable attributes = new Hashtable<>(); + attributes.put("Filter-Synctype", getSyncType()); + attributes.put("FilterType", filterType()); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + return Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java new file mode 100644 index 0000000..e0721d7 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java @@ -0,0 +1,39 @@ +package com.netflix.zuul.netty.filter; + +import com.netflix.zuul.filters.ZuulFilter_instrumentation; +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.handler.codec.http.HttpContent; + +@Weave(type = MatchType.BaseClass) +public abstract class BaseZuulFilterRunner { + + @Trace + protected void invokeNextStage(O zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"invokeNextStage"); + Weaver.callOriginal(); + } + + @Trace + protected O filter(ZuulFilter_instrumentation filter, I inMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + return Weaver.callOriginal(); + } + + @Trace + protected void invokeNextStage(O zuulMesg, HttpContent chunk) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"invokeNextStage"); + Weaver.callOriginal(); + } + + @Trace + protected void resume(O zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"resume"); + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java new file mode 100644 index 0000000..b391a19 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java @@ -0,0 +1,27 @@ +package com.netflix.zuul.netty.filter; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.handler.codec.http.HttpContent; + +@Weave(type = MatchType.Interface) +public abstract class FilterRunner { + + @Trace + public void filter(I zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + Weaver.callOriginal(); + } + + @Trace + public void filter(I zuulMesg, HttpContent chunk) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + Weaver.callOriginal(); + } + +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java new file mode 100644 index 0000000..c77ab71 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java @@ -0,0 +1,29 @@ +package com.netflix.zuul.netty.filter; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave +public abstract class ZuulFilterChainHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java new file mode 100644 index 0000000..78cd416 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java @@ -0,0 +1,36 @@ +package com.netflix.zuul.netty.insights; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class PassportStateHttpClientHandler { + + @Weave + public static class InboundHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } + + @Weave + public static class OutboundHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java new file mode 100644 index 0000000..7440f90 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java @@ -0,0 +1,45 @@ +package com.netflix.zuul.netty.insights; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class PassportStateHttpServerHandler { + + @Weave + public static class InboundHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } + + @Weave + public static class OutboundHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java new file mode 100644 index 0000000..0031437 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java @@ -0,0 +1,36 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class ClientRequestReceiver { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java new file mode 100644 index 0000000..2cacf79 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java @@ -0,0 +1,28 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave +public abstract class ClientResponseWriter { + + + @Trace(async = true) + public void channelRead(final ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java new file mode 100644 index 0000000..32ca929 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java @@ -0,0 +1,37 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave(type = MatchType.BaseClass) +public abstract class OriginResponseReceiver { + + @Trace(async = true) + public void channelRead(final ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java new file mode 100644 index 0000000..ab769be --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java @@ -0,0 +1,67 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.Collection; +import java.util.Collections; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; + +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +public class NettyRequestHeaders implements Headers { + + private HttpRequest request = null; + + public NettyRequestHeaders(HttpRequest req) { + request = req; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.getAll(name); + } + return Collections.emptyList(); + } + + @Override + public void setHeader(String name, String value) { + HttpHeaders headers = request.headers(); + headers.set(name, value); + } + + @Override + public void addHeader(String name, String value) { + HttpHeaders headers = request.headers(); + headers.add(name, value); + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + + return headers.names(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } + +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java new file mode 100644 index 0000000..afd8653 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java @@ -0,0 +1,22 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.Map; + +import com.netflix.zuul.message.http.HttpRequestInfo; + +public class Utils { + + public static void addAttribute(Map attributes, String key, Object value) { + if(attributes != null && key != null && !key.isEmpty() && value != null) { + attributes.put(key, value); + } + } + + public static void addRequestInfo(Map attributes, HttpRequestInfo info) { + if(info != null) { + addAttribute(attributes, "Request-Method", info.getMethod()); + addAttribute(attributes, "Request-Server", info.getServerName()); + addAttribute(attributes, "Request-OriginalHost", info.getOriginalHost()); + } + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java new file mode 100644 index 0000000..1f21355 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java @@ -0,0 +1,61 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.TransportType; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; + +public class ZuulDispatcher { + + private static volatile ZuulDispatcher instance = null; + public static final AtomicBoolean instrumented = new AtomicBoolean(false); + public static enum ChannelType {SERVER, CLIENT}; + + public static ZuulDispatcher get() { + if(instance == null) { + synchronized (ZuulDispatcher.class) { + if(instance == null) { + instance = new ZuulDispatcher(); + instrumented.set(true); + } + } + } + + return instance; + } + + private ZuulDispatcher() { + AgentBridge.instrumentation.retransformUninstrumentedClass(ZuulDispatcher.class); + } + + @Trace(dispatcher = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + + try { + ctx.pipeline().zuul_token = NewRelic.getAgent().getTransaction().getToken(); + + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + if(traced == null) { + NewRelic.getAgent().getLogger().log(Level.FINER, "Unable to dispatch "); + } else { + traced.setMetricName("Custom","Netflix-Zuul","ZuulDispatcher"); + HttpRequest request = (HttpRequest)msg; + NettyRequestHeaders inbound = new NettyRequestHeaders(request); + NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.HTTP, inbound); + } + } catch (Throwable e) { + AgentBridge.instrumentation.noticeInstrumentationError(e, Weaver.getImplementationTitle()); + } + finally { + AgentBridge.currentApiSource.remove(); + } + } +} diff --git a/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000..226ec24 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,11 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); + +} \ No newline at end of file diff --git a/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000..f00c416 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,20 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if (ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + +} \ No newline at end of file diff --git a/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000..304c6a0 --- /dev/null +++ b/netflix-zuul-core-2.1.6/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,15 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + + @NewField + public Token zuul_token; + +} diff --git a/netflix-zuul-core-2.1/build.gradle b/netflix-zuul-core-2.1/build.gradle new file mode 100644 index 0000000..274dc34 --- /dev/null +++ b/netflix-zuul-core-2.1/build.gradle @@ -0,0 +1,28 @@ + +// Build.gradle generated for instrumentation module netflix-zuul-core-2.1 + +apply plugin: 'java' + +dependencies { + implementation 'com.netflix.zuul:zuul-core:2.1.1' + implementation group: 'io.netty', name: 'netty-tcnative-boringssl-static', version: '2.0.7.Final' + + // New Relic Java Agent dependencies + implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0' + implementation 'com.newrelic.agent.java:newrelic-api:6.4.0' + implementation fileTree(include: ['*.jar'], dir: '../libs') + implementation fileTree(include: ['*.jar'], dir: '../test-lib') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.netflix-zuul-core-2.1' + attributes 'Implementation-Vendor': 'New Relic' + attributes 'Implementation-Vendor-Id': 'com.newrelic' + attributes 'Implementation-Version': 1.0 + } +} + +verifyInstrumentation { + passes 'com.netflix.zuul:zuul-core:[2.1.1,2.1.6)' +} \ No newline at end of file diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java new file mode 100644 index 0000000..5a1dec5 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpClientLifecycleChannelHandler.java @@ -0,0 +1,40 @@ +package com.netflix.netty.common; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class HttpClientLifecycleChannelHandler { + + @Weave + private static class HttpClientLifecycleInboundChannelHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + + } + + @Weave + private static class HttpClientLifecycleOutboundChannelHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + + } + + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java new file mode 100644 index 0000000..c5ac318 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpLifecycleChannelHandler_instrumentation.java @@ -0,0 +1,49 @@ +package com.netflix.netty.common; + +import com.netflix.netty.common.HttpLifecycleChannelHandler.CompleteReason; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.instrumentation.labs.netflix_zuul.NettyRequestHeaders; +import com.newrelic.instrumentation.labs.netflix_zuul.ZuulDispatcher; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; + +@Weave(originalName = "com.netflix.netty.common.HttpLifecycleChannelHandler") +public abstract class HttpLifecycleChannelHandler_instrumentation { + + + protected static boolean fireCompleteEventIfNotAlready(ChannelHandlerContext_Instrumentation ctx, CompleteReason reason) { + boolean b = Weaver.callOriginal(); + if(b) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.expire(); + ctx.pipeline().zuul_token = null; + } + } + + return b; + } + + protected static boolean fireStartEvent(ChannelHandlerContext_Instrumentation ctx, HttpRequest request) { + boolean b = Weaver.callOriginal(); + if(b) { + ZuulDispatcher.get().channelRead(ctx, request); + NettyRequestHeaders headers = new NettyRequestHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + if(ctx.pipeline().zuul_token == null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if(t != null && t.isActive()) { + ctx.pipeline().zuul_token= t; + } else if(t != null) { + t.expire(); + t = null; + } + } + } + + return b; + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java new file mode 100644 index 0000000..6589b7e --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/netty/common/HttpServerLifecycleChannelHandler.java @@ -0,0 +1,38 @@ +package com.netflix.netty.common; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class HttpServerLifecycleChannelHandler { + + @Weave + private static class HttpServerLifecycleInboundChannelHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } + + @Weave + private static class HttpServerLifecycleOutboundChannelHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/RequestCompleteHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/RequestCompleteHandler.java new file mode 100644 index 0000000..73f8144 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/RequestCompleteHandler.java @@ -0,0 +1,27 @@ +package com.netflix.zuul; + +import java.util.HashMap; + +import com.netflix.zuul.message.http.HttpRequestInfo; +import com.netflix.zuul.message.http.HttpResponseMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.instrumentation.labs.netflix_zuul.Utils; + +@Weave(type = MatchType.Interface) +public class RequestCompleteHandler { + + @Trace + public void handle(HttpRequestInfo inboundRequest, HttpResponseMessage response) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + HashMap attributes = new HashMap<>(); + Utils.addRequestInfo(attributes, inboundRequest); + traced.addCustomAttribute("In", inboundRequest.getMethod()); + traced.setMetricName("Custom","Netflix","Zuul","RequestCompleteHandler",getClass().getSimpleName(),"handle"); + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java new file mode 100644 index 0000000..c0e795c --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/SyncZuulFilter.java @@ -0,0 +1,24 @@ +package com.netflix.zuul.filters; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface) +public abstract class SyncZuulFilter implements ZuulFilter { + + @Trace(dispatcher = true) + public O apply(I input) { + String filterName = filterName(); + if(filterName != null && !filterName.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","SyncZuulFilter",filterName,"apply"); + } else { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","SyncZuulFilter",getClass().getSimpleName(),"apply"); + } + return Weaver.callOriginal(); + } + +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java new file mode 100644 index 0000000..621b5ac --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/filters/ZuulFilter_instrumentation.java @@ -0,0 +1,35 @@ +package com.netflix.zuul.filters; + +import java.util.Hashtable; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import rx.Observable; + +@Weave(type=MatchType.Interface, originalName = "com.netflix.zuul.filters.ZuulFilter") +public abstract class ZuulFilter_instrumentation { + + public abstract FilterSyncType getSyncType(); + public abstract String filterName(); + public abstract FilterType filterType(); + + @Trace(dispatcher = true) + public Observable applyAsync(I input) { + String filterName = filterName(); + if(filterName != null && !filterName.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","ZuulFilter",filterName,"applyAsync"); + } else { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix-Zuul","ZuulFilter",getClass().getSimpleName(),"applyAsync"); + } + Hashtable attributes = new Hashtable<>(); + attributes.put("Filter-Synctype", getSyncType()); + attributes.put("FilterType", filterType()); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + return Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java new file mode 100644 index 0000000..75d5a0f --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/BaseZuulFilterRunner.java @@ -0,0 +1,39 @@ +package com.netflix.zuul.netty.filter; + +import com.netflix.zuul.filters.ZuulFilter_instrumentation; +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.handler.codec.http.HttpContent; + +@Weave(type = MatchType.BaseClass) +public abstract class BaseZuulFilterRunner { + + @Trace(dispatcher=true) + protected void invokeNextStage(O zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"invokeNextStage"); + Weaver.callOriginal(); + } + + @Trace(dispatcher=true) + protected O filter(ZuulFilter_instrumentation filter, I inMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + return Weaver.callOriginal(); + } + + @Trace(dispatcher=true) + protected void invokeNextStage(O zuulMesg, HttpContent chunk) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"invokeNextStage"); + Weaver.callOriginal(); + } + + @Trace(dispatcher=true) + protected void resume(O zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"resume"); + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java new file mode 100644 index 0000000..78bc0cc --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/FilterRunner.java @@ -0,0 +1,27 @@ +package com.netflix.zuul.netty.filter; + +import com.netflix.zuul.message.ZuulMessage; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.handler.codec.http.HttpContent; + +@Weave(type = MatchType.Interface) +public abstract class FilterRunner { + + @Trace(dispatcher=true) + public void filter(I zuulMesg) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + Weaver.callOriginal(); + } + + @Trace(dispatcher=true) + public void filter(I zuulMesg, HttpContent chunk) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Netflix","Zuul",getClass().getSimpleName(),"filter"); + Weaver.callOriginal(); + } + +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java new file mode 100644 index 0000000..c77ab71 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/filter/ZuulFilterChainHandler.java @@ -0,0 +1,29 @@ +package com.netflix.zuul.netty.filter; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave +public abstract class ZuulFilterChainHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java new file mode 100644 index 0000000..1077157 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpClientHandler.java @@ -0,0 +1,36 @@ +package com.netflix.zuul.netty.insights; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class PassportStateHttpClientHandler { + + @Weave + private static class InboundHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } + + @Weave + private static class OutboundHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java new file mode 100644 index 0000000..df1142a --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/insights/PassportStateHttpServerHandler.java @@ -0,0 +1,45 @@ +package com.netflix.zuul.netty.insights; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class PassportStateHttpServerHandler { + + @Weave + private static class InboundHandler { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + } + + @Weave + private static class OutboundHandler { + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java new file mode 100644 index 0000000..0031437 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java @@ -0,0 +1,36 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave +public abstract class ClientRequestReceiver { + + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java new file mode 100644 index 0000000..2cacf79 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/ClientResponseWriter.java @@ -0,0 +1,28 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave +public abstract class ClientResponseWriter { + + + @Trace(async = true) + public void channelRead(final ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java new file mode 100644 index 0000000..32ca929 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java @@ -0,0 +1,37 @@ +package com.netflix.zuul.netty.server; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPromise; + +@Weave(type = MatchType.BaseClass) +public abstract class OriginResponseReceiver { + + @Trace(async = true) + public void channelRead(final ChannelHandlerContext_Instrumentation ctx, Object msg) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void userEventTriggered(ChannelHandlerContext_Instrumentation ctx, Object evt) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } + + @Trace(async = true) + public void write(ChannelHandlerContext_Instrumentation ctx, Object msg, ChannelPromise promise) { + if(ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + Weaver.callOriginal(); + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java new file mode 100644 index 0000000..ab769be --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/NettyRequestHeaders.java @@ -0,0 +1,67 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.Collection; +import java.util.Collections; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; + +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +public class NettyRequestHeaders implements Headers { + + private HttpRequest request = null; + + public NettyRequestHeaders(HttpRequest req) { + request = req; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.getAll(name); + } + return Collections.emptyList(); + } + + @Override + public void setHeader(String name, String value) { + HttpHeaders headers = request.headers(); + headers.set(name, value); + } + + @Override + public void addHeader(String name, String value) { + HttpHeaders headers = request.headers(); + headers.add(name, value); + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + + return headers.names(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } + +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java new file mode 100644 index 0000000..afd8653 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/Utils.java @@ -0,0 +1,22 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.Map; + +import com.netflix.zuul.message.http.HttpRequestInfo; + +public class Utils { + + public static void addAttribute(Map attributes, String key, Object value) { + if(attributes != null && key != null && !key.isEmpty() && value != null) { + attributes.put(key, value); + } + } + + public static void addRequestInfo(Map attributes, HttpRequestInfo info) { + if(info != null) { + addAttribute(attributes, "Request-Method", info.getMethod()); + addAttribute(attributes, "Request-Server", info.getServerName()); + addAttribute(attributes, "Request-OriginalHost", info.getOriginalHost()); + } + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java new file mode 100644 index 0000000..1f21355 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/com/newrelic/instrumentation/labs/netflix_zuul/ZuulDispatcher.java @@ -0,0 +1,61 @@ +package com.newrelic.instrumentation.labs.netflix_zuul; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.TransportType; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; + +public class ZuulDispatcher { + + private static volatile ZuulDispatcher instance = null; + public static final AtomicBoolean instrumented = new AtomicBoolean(false); + public static enum ChannelType {SERVER, CLIENT}; + + public static ZuulDispatcher get() { + if(instance == null) { + synchronized (ZuulDispatcher.class) { + if(instance == null) { + instance = new ZuulDispatcher(); + instrumented.set(true); + } + } + } + + return instance; + } + + private ZuulDispatcher() { + AgentBridge.instrumentation.retransformUninstrumentedClass(ZuulDispatcher.class); + } + + @Trace(dispatcher = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + + try { + ctx.pipeline().zuul_token = NewRelic.getAgent().getTransaction().getToken(); + + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + if(traced == null) { + NewRelic.getAgent().getLogger().log(Level.FINER, "Unable to dispatch "); + } else { + traced.setMetricName("Custom","Netflix-Zuul","ZuulDispatcher"); + HttpRequest request = (HttpRequest)msg; + NettyRequestHeaders inbound = new NettyRequestHeaders(request); + NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.HTTP, inbound); + } + } catch (Throwable e) { + AgentBridge.instrumentation.noticeInstrumentationError(e, Weaver.getImplementationTitle()); + } + finally { + AgentBridge.currentApiSource.remove(); + } + } +} diff --git a/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000..226ec24 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,11 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); + +} \ No newline at end of file diff --git a/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000..f00c416 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,20 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if (ctx.pipeline().zuul_token != null) { + ctx.pipeline().zuul_token.link(); + } + + Weaver.callOriginal(); + } + +} \ No newline at end of file diff --git a/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000..304c6a0 --- /dev/null +++ b/netflix-zuul-core-2.1/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,15 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + + @NewField + public Token zuul_token; + +} diff --git a/settings.gradle b/settings.gradle index 67070a5..e6da00f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,5 @@ rootProject.name = 'java-instrumentation-template' +include 'netflix-zuul-core-1.x' +include 'netflix-zuul-core-2.1' +include 'netflix-zuul-core-2.1.6' +include 'spring-zuul' diff --git a/spring-zuul/build.gradle b/spring-zuul/build.gradle new file mode 100644 index 0000000..9e36749 --- /dev/null +++ b/spring-zuul/build.gradle @@ -0,0 +1,31 @@ + +// Build.gradle generated for instrumentation module spring-zuul + +apply plugin: 'java' + +dependencies { + implementation group: 'org.springframework.cloud', name: 'spring-cloud-netflix-zuul', version: '2.0.0.RELEASE' + implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.0.7.RELEASE' + compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' + + // New Relic Java Agent dependencies + implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0' + implementation 'com.newrelic.agent.java:newrelic-api:6.4.0' + implementation fileTree(include: ['*.jar'], dir: '../libs') + implementation fileTree(include: ['*.jar'], dir: '../test-lib') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-zuul' + attributes 'Implementation-Vendor': 'New Relic' + attributes 'Implementation-Vendor-Id': 'com.newrelic' + attributes 'Implementation-Version': 1.0 + } +} + +verifyInstrumentation { + passes('org.springframework.cloud:spring-cloud-netflix-zuul:[2.0.0.RELEASE,)') { + compile('org.springframework:spring-webmvc:5.0.7.RELEASE') + } +} \ No newline at end of file diff --git a/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/RouteLocator.java b/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/RouteLocator.java new file mode 100644 index 0000000..0f5ba91 --- /dev/null +++ b/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/RouteLocator.java @@ -0,0 +1,41 @@ +package org.springframework.cloud.netflix.zuul.filters; + +import java.util.HashMap; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface) +public abstract class RouteLocator { + + public Route getMatchingRoute(String path) { + + Route route = Weaver.callOriginal(); + if(route != null) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + HashMap attributes = new HashMap<>(); + String id = route.getId(); + if(id != null && !id.isEmpty()) { + attributes.put("Route-ID", id); + } + String full = route.getFullPath(); + if(full != null && !full.isEmpty()) { + attributes.put("Route-FullPath", full); + } + String routePath = route.getPath(); + if(routePath != null && !routePath.isEmpty()) { + attributes.put("Route-Path", routePath); + } + String location = route.getLocation(); + if(location != null && !location.isEmpty()) { + attributes.put("Route-Location", location); + } + traced.addCustomAttributes(attributes); + } + + return route; + } +} diff --git a/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/web/ZuulController.java b/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/web/ZuulController.java new file mode 100644 index 0000000..33e1178 --- /dev/null +++ b/spring-zuul/src/main/java/org/springframework/cloud/netflix/zuul/web/ZuulController.java @@ -0,0 +1,33 @@ +package org.springframework.cloud.netflix.zuul.web; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave +public abstract class ZuulController { + + @Trace + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { + String matching = (String) request.getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingPattern"); + String method = request.getMethod(); + if(matching != null && !matching.isEmpty()) { + NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.CUSTOM_LOW, false, "Spring MVC", matching, method); + } else { + matching = (String) request.getAttribute("\"org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping"); + if(matching != null && !matching.isEmpty()) { + NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.CUSTOM_LOW, false, "Spring MVC", matching, method); + } + } + ModelAndView modelView = Weaver.callOriginal(); + + return modelView; + } +}