Repository: knox Updated Branches: refs/heads/master c59bfeb3a -> d88a2878c
KNOX-597: Improve diagnostic logging of HTTP traffic Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/d88a2878 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/d88a2878 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/d88a2878 Branch: refs/heads/master Commit: d88a2878c182d484f388519134b817c501354708 Parents: c59bfeb Author: Kevin Minder <[email protected]> Authored: Thu Sep 10 17:38:00 2015 -0400 Committer: Kevin Minder <[email protected]> Committed: Thu Sep 10 17:38:00 2015 -0400 ---------------------------------------------------------------------- .../home/conf/gateway-log4j.properties | 31 ++++++++ .../apache/hadoop/gateway/GatewayFilter.java | 13 ++- .../apache/hadoop/gateway/GatewayServer.java | 27 ++++++- .../gateway/filter/CorrelationHandler.java | 45 +++++++++++ .../hadoop/gateway/filter/TraceFilter.java | 37 --------- .../hadoop/gateway/trace/AccessHandler.java | 53 +++++++++++++ .../hadoop/gateway/trace/ErrorHandler.java | 42 ++++++++++ .../hadoop/gateway/trace/TraceHandler.java | 54 +++++++++++++ .../apache/hadoop/gateway/trace/TraceInput.java | 70 +++++++++++++++++ .../hadoop/gateway/trace/TraceOutput.java | 75 ++++++++++++++++++ .../hadoop/gateway/trace/TraceRequest.java | 83 ++++++++++++++++++++ .../hadoop/gateway/trace/TraceResponse.java | 77 ++++++++++++++++++ .../apache/hadoop/gateway/trace/TraceUtil.java | 72 +++++++++++++++++ 13 files changed, 636 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-release/home/conf/gateway-log4j.properties ---------------------------------------------------------------------- diff --git a/gateway-release/home/conf/gateway-log4j.properties b/gateway-release/home/conf/gateway-log4j.properties index 3ad09a9..67d8e9d 100644 --- a/gateway-release/home/conf/gateway-log4j.properties +++ b/gateway-release/home/conf/gateway-log4j.properties @@ -47,3 +47,34 @@ log4j.appender.auditfile.Append = true log4j.appender.auditfile.DatePattern = '.'yyyy-MM-dd log4j.appender.auditfile.layout = org.apache.hadoop.gateway.audit.log4j.layout.AuditLayout +#log4j.logger.org.apache.hadoop.gateway.access=TRACE,httpaccess +#log4j.additivity.org.apache.hadoop.gateway.access=false + +#log4j.logger.org.apache.hadoop.gateway.http=TRACE,httpserver +#log4j.additivity.org.apache.hadoop.gateway.http=false +##log4j.logger.org.apache.hadoop.gateway.http.request.headers=OFF +##log4j.logger.org.apache.hadoop.gateway.http.response.headers=OFF +##log4j.logger.org.apache.hadoop.gateway.http.request.body=OFF +##log4j.logger.org.apache.hadoop.gateway.http.response.body=OFF + +#log4j.logger.org.apache.http.wire=DEBUG,httpclient +#log4j.additivity.org.apache.http.wire=false + +#log4j.appender.httpaccess=org.apache.log4j.DailyRollingFileAppender +#log4j.appender.httpaccess.File=${app.log.dir}/${launcher.name}-http-access.log +#log4j.appender.httpaccess.DatePattern=.yyyy-MM-dd +#log4j.appender.httpaccess.layout=org.apache.log4j.PatternLayout +#log4j.appender.httpaccess.layout.ConversionPattern=%d{ISO8601}|%t|%m%n + +#log4j.appender.httpserver=org.apache.log4j.DailyRollingFileAppender +#log4j.appender.httpserver.File=${app.log.dir}/${launcher.name}-http-server.log +#log4j.appender.httpserver.DatePattern=.yyyy-MM-dd +#log4j.appender.httpserver.layout=org.apache.log4j.PatternLayout +#log4j.appender.httpserver.layout.ConversionPattern=%d{ISO8601}|%t|%m%n + +#log4j.appender.httpclient=org.apache.log4j.DailyRollingFileAppender +#log4j.appender.httpclient.File=${app.log.dir}/${launcher.name}-http-client.log +#log4j.appender.httpclient.DatePattern=.yyyy-MM-dd +#log4j.appender.httpclient.layout=org.apache.log4j.PatternLayout +#log4j.appender.httpclient.layout.ConversionPattern=%d{ISO8601}|%t|%m%n + http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java index df72885..3ff0abd 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java @@ -189,10 +189,17 @@ public class GatewayFilter implements Filter { Holder holder = new Holder( path, name, clazz, params, resourceRole ); addHolder( holder ); } - + + // Now creating the correlation context only if required since it may be created upstream in the CorrelationHandler. private void assignCorrelationRequestId() { - CorrelationContext correlationContext = CorrelationServiceFactory.getCorrelationService().createContext(); - correlationContext.setRequestId( UUID.randomUUID().toString() ); + CorrelationContext correlationContext = CorrelationServiceFactory.getCorrelationService().getContext(); + if( correlationContext == null ) { + correlationContext = CorrelationServiceFactory.getCorrelationService().createContext(); + } + String requestId = correlationContext.getRequestId(); + if( requestId == null ) { + correlationContext.setRequestId( UUID.randomUUID().toString() ); + } } private class Chain implements FilterChain { http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java index b6e44c3..4e1f963 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java @@ -30,21 +30,27 @@ import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants; import org.apache.hadoop.gateway.config.GatewayConfig; import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl; import org.apache.hadoop.gateway.deploy.DeploymentFactory; +import org.apache.hadoop.gateway.filter.CorrelationHandler; import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory; import org.apache.hadoop.gateway.services.GatewayServices; import org.apache.hadoop.gateway.services.ServiceLifecycleException; -import org.apache.hadoop.gateway.services.topology.TopologyService; import org.apache.hadoop.gateway.services.registry.ServiceRegistry; import org.apache.hadoop.gateway.services.security.SSLService; +import org.apache.hadoop.gateway.services.topology.TopologyService; import org.apache.hadoop.gateway.topology.Topology; import org.apache.hadoop.gateway.topology.TopologyEvent; import org.apache.hadoop.gateway.topology.TopologyListener; +import org.apache.hadoop.gateway.trace.AccessHandler; +import org.apache.hadoop.gateway.trace.ErrorHandler; +import org.apache.hadoop.gateway.trace.TraceHandler; import org.apache.log4j.PropertyConfigurator; import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.ErrorHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.webapp.WebAppContext; import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; import org.jboss.shrinkwrap.api.spec.WebArchive; @@ -306,7 +312,21 @@ public class GatewayServer { connector.setPort(address.getPort()); jetty.addConnector(connector); } - jetty.setHandler( contexts ); + + HandlerCollection handlers = new HandlerCollection(); + RequestLogHandler logHandler = new RequestLogHandler(); + logHandler.setRequestLog( new AccessHandler() ); + + TraceHandler traceHandler = new TraceHandler(); + traceHandler.setHandler( contexts ); + traceHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) ); + + CorrelationHandler correlationHandler = new CorrelationHandler(); + correlationHandler.setHandler( traceHandler ); + + handlers.setHandlers( new Handler[]{ correlationHandler, logHandler } ); + + jetty.setHandler( handlers ); try { jetty.start(); } @@ -357,6 +377,7 @@ public class GatewayServer { String warPath = warFile.getAbsolutePath(); errorHandler = new ErrorHandler(); errorHandler.setShowStacks(false); + errorHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) ); WebAppContext context = new WebAppContext(); context.setDefaultsDescriptor( null ); if (!name.equals("_default")) { http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/CorrelationHandler.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/CorrelationHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/CorrelationHandler.java new file mode 100644 index 0000000..47f9723 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/CorrelationHandler.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.filter; + +import org.apache.hadoop.gateway.audit.api.CorrelationContext; +import org.apache.hadoop.gateway.audit.api.CorrelationServiceFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.HandlerWrapper; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.UUID; + +public class CorrelationHandler extends HandlerWrapper { + + @Override + public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) + throws IOException, ServletException { + CorrelationContext correlationContext = CorrelationServiceFactory.getCorrelationService().createContext(); + correlationContext.setRequestId( UUID.randomUUID().toString() ); + try { + super.handle( target, baseRequest, request, response ); + } finally { + correlationContext.destroy(); + } + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/TraceFilter.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/TraceFilter.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/TraceFilter.java deleted file mode 100644 index 5ea35a5..0000000 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/TraceFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.hadoop.gateway.filter; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * - */ -//TODO: Implement the trace filter. -public class TraceFilter extends AbstractGatewayFilter { - - @Override - public void doFilter( HttpServletRequest request, HttpServletResponse response, FilterChain chain ) throws IOException, ServletException { - chain.doFilter( request, response ); - } - -} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/AccessHandler.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/AccessHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/AccessHandler.java new file mode 100644 index 0000000..fe2e174 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/AccessHandler.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.log4j.Logger; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.RequestLog; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.component.AbstractLifeCycle; + +public class AccessHandler extends AbstractLifeCycle implements RequestLog { + + private static Logger log = Logger.getLogger( "org.apache.hadoop.gateway.access" ); + + @Override + public void log( Request request, Response response ) { + if( log.isTraceEnabled() ) { + StringBuilder sb = new StringBuilder(); + TraceUtil.appendCorrelationContext( sb ); + sb.append( "|" ); + sb.append( request.getRemoteAddr() ); + sb.append( "|" ); + sb.append( request.getMethod() ); + sb.append( "|" ); + sb.append( request.getUri().toString() ); + sb.append( "|" ); + sb.append( request.getContentLength() ); + sb.append( "|" ); + sb.append( response.getStatus() ); + sb.append( "|" ); + sb.append( response.getContentCount() ); + sb.append( "|" ); + sb.append( System.currentTimeMillis() - request.getTimeStamp() ); + log.trace( sb ); + } + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/ErrorHandler.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/ErrorHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/ErrorHandler.java new file mode 100644 index 0000000..a1fb87b --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/ErrorHandler.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.eclipse.jetty.server.Request; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +public class ErrorHandler extends org.eclipse.jetty.server.handler.ErrorHandler { + + private Set<Integer> bodyFilter; + + public void setTracedBodyFilter( String s ) { + bodyFilter = TraceUtil.parseIntegerSet( s ); + } + + @Override + public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) + throws IOException { + HttpServletResponse traceResponse = new TraceResponse( response, bodyFilter ); + super.handle( target, baseRequest, request, traceResponse ); + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceHandler.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceHandler.java new file mode 100644 index 0000000..7f49979 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceHandler.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.HandlerWrapper; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +public class TraceHandler extends HandlerWrapper { + + static String HTTP_LOGGER = "org.apache.hadoop.gateway.http"; + static String HTTP_REQUEST_LOGGER = HTTP_LOGGER + ".request"; + static String HTTP_REQUEST_HEADER_LOGGER = HTTP_REQUEST_LOGGER + ".headers"; + static String HTTP_REQUEST_BODY_LOGGER = HTTP_REQUEST_LOGGER + ".body"; + + static String HTTP_RESPONSE_LOGGER = HTTP_LOGGER + ".response"; + static String HTTP_RESPONSE_HEADER_LOGGER = HTTP_RESPONSE_LOGGER + ".headers"; + static String HTTP_RESPONSE_BODY_LOGGER = HTTP_RESPONSE_LOGGER + ".body"; + + private Set<Integer> bodyFilter; + + public void setTracedBodyFilter( String s ) { + bodyFilter = TraceUtil.parseIntegerSet( s ); + } + + @Override + public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) + throws IOException, ServletException { + HttpServletRequest newRequest = new TraceRequest( request ); + HttpServletResponse newResponse = new TraceResponse( response, bodyFilter ); + super.handle( target, baseRequest, newRequest, newResponse ); + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceInput.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceInput.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceInput.java new file mode 100644 index 0000000..3d10538 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceInput.java @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.log4j.Logger; + +import javax.servlet.ServletInputStream; +import java.io.IOException; + +class TraceInput extends ServletInputStream { + + private static Logger log = Logger.getLogger( TraceHandler.HTTP_REQUEST_LOGGER ); + private static Logger bodyLog = Logger.getLogger( TraceHandler.HTTP_REQUEST_BODY_LOGGER ); + + private ServletInputStream delegate; + + private static final int BUFFER_LIMIT = 1024; + private StringBuilder buffer = new StringBuilder( BUFFER_LIMIT ); + + TraceInput( ServletInputStream delegate ) { + this.delegate = delegate; + } + + @Override + public int read() throws IOException { + int b = delegate.read(); + if( b >= 0 ) { + buffer.append( (char)b ); + if( buffer.length() == BUFFER_LIMIT || delegate.available() == 0 ) { + traceBody(); + } + } + return b; + } + + @Override + public void close() throws IOException { + traceBody(); + delegate.close(); + } + + private synchronized void traceBody() { + if( buffer.length() > 0 ) { + String body = buffer.toString(); + buffer.setLength( 0 ); + StringBuilder sb = new StringBuilder(); + TraceUtil.appendCorrelationContext( sb ); + sb.append( String.format( "|RequestBody[%d]\n\t%s", body.length(), body ) ); + if( bodyLog.isTraceEnabled() ) { + log.trace( sb.toString() ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceOutput.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceOutput.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceOutput.java new file mode 100644 index 0000000..cec59b3 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceOutput.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.log4j.Logger; + +import javax.servlet.ServletOutputStream; +import java.io.IOException; + +class TraceOutput extends ServletOutputStream { + + private static Logger log = Logger.getLogger( TraceHandler.HTTP_RESPONSE_LOGGER ); + private static Logger bodyLog = Logger.getLogger( TraceHandler.HTTP_RESPONSE_BODY_LOGGER ); + + private ServletOutputStream delegate; + + private static final int BUFFER_LIMIT = 1024; + private StringBuilder buffer = new StringBuilder( BUFFER_LIMIT ); + + TraceOutput( ServletOutputStream delegate ) { + this.delegate = delegate; + } + + @Override + public synchronized void write( int b ) throws IOException { + if( b >= 0 ) { + buffer.append( (char)b ); + if( buffer.length() == BUFFER_LIMIT ) { + traceBody(); + } + } + delegate.write( b ); + } + + @Override + public void flush() throws IOException { + traceBody(); + delegate.flush(); + } + + @Override + public void close() throws IOException { + traceBody(); + delegate.close(); + } + + private synchronized void traceBody() { + if( buffer.length() > 0 ) { + String body = buffer.toString(); + buffer.setLength( 0 ); + StringBuilder sb = new StringBuilder(); + TraceUtil.appendCorrelationContext( sb ); + sb.append( String.format( "|ResponseBody[%d]\n\t%s", body.length(), body ) ); + if( bodyLog.isTraceEnabled() ) { + log.trace( sb.toString() ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceRequest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceRequest.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceRequest.java new file mode 100644 index 0000000..3211c50 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceRequest.java @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.log4j.Logger; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; +import java.util.Enumeration; + +class TraceRequest extends HttpServletRequestWrapper { + + private static Logger log = Logger.getLogger( TraceHandler.HTTP_REQUEST_LOGGER ); + private static Logger headLog = Logger.getLogger( TraceHandler.HTTP_REQUEST_HEADER_LOGGER ); + + private ServletInputStream input; + + TraceRequest( HttpServletRequest request ) { + super( request ); + if( log.isTraceEnabled() ) { + traceRequestDetails(); + } + } + + public synchronized ServletInputStream getInputStream() throws IOException { + if( log.isTraceEnabled() ) { + if( input == null ) { + input = new TraceInput( super.getInputStream() ); + } + return input; + } else { + return super.getInputStream(); + } + } + + private void traceRequestDetails() { + StringBuilder sb = new StringBuilder(); + TraceUtil.appendCorrelationContext( sb ); + sb.append( "|Request=" ); + sb.append( getMethod() ); + sb.append( " " ); + sb.append( getRequestURI() ); + String qs = getQueryString(); + if( qs != null ) { + sb.append( "?" ); + sb.append( qs ); + } + appendHeaders( sb ); + log.trace( sb.toString() ); + } + + private void appendHeaders( StringBuilder sb ) { + if( headLog.isTraceEnabled() ) { + Enumeration<String> names = getHeaderNames(); + while( names.hasMoreElements() ) { + String name = names.nextElement(); + Enumeration<String> values = getHeaders( name ); + while( values.hasMoreElements() ) { + String value = values.nextElement(); + sb.append( String.format( "\n\tHeader[%s]=%s", name, value ) ); + } + } + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceResponse.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceResponse.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceResponse.java new file mode 100644 index 0000000..632fa86 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceResponse.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.log4j.Logger; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Collection; +import java.util.Set; + +class TraceResponse extends HttpServletResponseWrapper { + + private static Logger log = Logger.getLogger( TraceHandler.HTTP_RESPONSE_LOGGER ); + private static Logger headLog = Logger.getLogger( TraceHandler.HTTP_RESPONSE_HEADER_LOGGER ); + + private ServletOutputStream output; + private Set<Integer> filter; + + + TraceResponse( HttpServletResponse response, Set<Integer> filter ) { + super( response ); + this.filter = filter; + } + + public synchronized ServletOutputStream getOutputStream() throws IOException { + if( log.isTraceEnabled() ) { + traceResponseDetails(); + if( output == null && ( filter == null || filter.isEmpty() || filter.contains( getStatus() ) ) ) { + output = new TraceOutput( super.getOutputStream() ); + } + return output; + } else { + return super.getOutputStream(); + } + } + + private void traceResponseDetails() { + StringBuilder sb = new StringBuilder(); + TraceUtil.appendCorrelationContext( sb ); + sb.append( "|Response=" ); + sb.append( getStatus() ); + appendHeaders( sb ); + log.trace( sb.toString() ); + } + + private void appendHeaders( StringBuilder sb ) { + if( headLog.isTraceEnabled() ) { + Collection<String> names = getHeaderNames(); + for( String name : names ) { + for( String value : getHeaders( name ) ) { + sb.append( String.format( "\n\tHeader[%s]=%s", name, value ) ); + } + } + } + } + +} + + http://git-wip-us.apache.org/repos/asf/knox/blob/d88a2878/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceUtil.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceUtil.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceUtil.java new file mode 100644 index 0000000..59e4064 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/trace/TraceUtil.java @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.gateway.trace; + +import org.apache.hadoop.gateway.audit.api.CorrelationContext; +import org.apache.hadoop.gateway.audit.api.CorrelationService; +import org.apache.hadoop.gateway.audit.api.CorrelationServiceFactory; + +import java.util.HashSet; +import java.util.Set; +import java.util.StringTokenizer; + +public class TraceUtil { + + private static CorrelationService cs = CorrelationServiceFactory.getCorrelationService(); + + final static void appendCorrelationContext( final StringBuilder sb ) { + CorrelationContext cc = cs.getContext(); + if( cc == null ) { + sb.append( "||" ); + } else { + append( sb, cc.getRootRequestId() ); + sb.append( "|" ); + append( sb, cc.getParentRequestId() ); + sb.append( "|" ); + append( sb, cc.getRequestId() ); + } + } + + private static final void append( final StringBuilder sb, final String s ) { + if( s != null ) { + sb.append( s ); + } + } + + final static Set<Integer> parseIntegerSet( String str ) { + Set<Integer> set = new HashSet<Integer>(); + if( str != null && !str.trim().isEmpty() ) { + StringTokenizer parser = new StringTokenizer( str.trim(), ",", false ); + while( parser.hasMoreTokens() ) { + addParsedIntegerToSet( set, parser.nextToken() ); + } + } + return set; + } + + private static final void addParsedIntegerToSet( Set<Integer> set, String str ) { + if( str != null && !str.trim().isEmpty() ) { + try { + set.add( new Integer( str.trim() ) ); + } catch( NumberFormatException e ) { + // Ignore it. + } + } + } + +}
