Skip to content

Commit

Permalink
Add Java Flight Recorder event for JaxRS requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Whiting committed Jan 27, 2021
1 parent 2056489 commit 455bdda
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.commonjava.util.gateway.exception.mapper;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This default mapper allows any exception to be captured ensuring a ResponseContextFilter is always called.
*/
@Provider
public class UnhandledThrowableHandler
implements ExceptionMapper<Throwable>//, RestProvider
{
public Response toResponse( Throwable exception )
{
Logger logger = LoggerFactory.getLogger( getClass() );
logger.error( "Unhandled exception: " + exception.getMessage(), exception );

return Response.status( Response.Status.INTERNAL_SERVER_ERROR )
.entity( ExceptionUtils.getStackTrace( exception ) )
.type( MediaType.TEXT_PLAIN )
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (C) 2011-2021 Red Hat, Inc. (https://github.com/Commonjava/indy)
*
* Licensed 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.commonjava.util.gateway.exception.mapper;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This WebApplicationException handler will check for a HTTP response status
* code (SC) in the exception and ensure the client will receive the corresponding SC code.
*/
public class UnhandledWebApplicationExceptionHandler
implements ExceptionMapper<WebApplicationException>
{
@Override
public Response toResponse( WebApplicationException exception )
{
Response response = null;
if ( exception.getResponse() != null && exception.getResponse().getStatusInfo() != null )
{
logger.error( "Unhandled exception: " + exception.getMessage(), exception );

response = Response.status( exception.getResponse().getStatusInfo() )
.entity( ExceptionUtils.getStackTrace( exception ) )
.type( MediaType.TEXT_PLAIN )
.build();
}
else
{
response = new UnhandledThrowableHandler().toResponse( exception );
}
return response;
}

private static final Logger logger = LoggerFactory
.getLogger( UnhandledWebApplicationExceptionHandler.class.getName() );

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.commonjava.util.gateway.metrics.jfr;

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;

import org.commonjava.util.gateway.metrics.jfr.events.JaxRSEvent;
import org.jboss.resteasy.core.ResourceMethodInvoker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Purpose of this filter is to generate events for JaxRS calls when profiling is enabled.
*
*/
@Provider
public class FlightRecorderFilter implements ContainerRequestFilter, ContainerResponseFilter
{
@Override
public void filter( ContainerRequestContext requestContext ) throws IOException
{
logger.trace("processing request context");
final JaxRSEvent event = new JaxRSEvent();
final boolean isEnabled = event.isEnabled();
if ( !isEnabled )
{
return;
}
event.begin();
requestContext.setProperty( JaxRSEvent.NAME, event );
}

@Override
public void filter( ContainerRequestContext requestContext, ContainerResponseContext responseContext )
throws IOException
{
logger.trace("processing response context");
if ( requestContext == null )
{
logger.error( "request context is null" );
return;
}
Object prop = requestContext.getProperty( JaxRSEvent.NAME );
if ( prop == null )
{
return;
}
JaxRSEvent event = ( JaxRSEvent ) prop;
if ( !event.isEnabled() )
{
return;
}

event.end();

if ( event.shouldCommit() )
{
event.method = requestContext.getMethod();
event.mediaType = String.valueOf ( requestContext.getMediaType() ) ;
event.length = requestContext.getLength();
event.methodFrameName = getMethodName( requestContext );
event.path = requestContext.getUriInfo().getPath();
event.responseLength = responseContext.getLength();
event.status = responseContext.getStatus();

event.commit();
}
}

private String getMethodName( ContainerRequestContext context )
{
Object p = context.getProperty( METHOD_NAME );
if ( p == null )
{
return "";
}
if ( p instanceof ResourceMethodInvoker )
{
ResourceMethodInvoker invoker = (ResourceMethodInvoker) p;
return invoker.getMethod().getName();
}
else
{
return "";
}
}

private static final String METHOD_NAME = ResourceMethodInvoker.class.getName();
private static final Logger logger = LoggerFactory.getLogger( FlightRecorderFilter.class.getName() );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.commonjava.util.gateway.metrics.jfr;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;

import org.commonjava.util.gateway.metrics.jfr.events.JaxRSEvent;

import io.quarkus.runtime.StartupEvent;
import jdk.jfr.FlightRecorder;

@ApplicationScoped
public class FlightRecorderMetrics
{
public void registerEvents( @Observes StartupEvent e )
{
FlightRecorder.register( JaxRSEvent.class );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.commonjava.util.gateway.metrics.jfr.events;

import jdk.jfr.Category;
import jdk.jfr.DataAmount;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;

@Name ( JaxRSEvent.NAME )
@Label ( "Invocation" )
@Category ( "JaxRS" )
@Description ( "JaxRS invocation event" )
@StackTrace ( false )
public class JaxRSEvent extends Event
{
public static final String NAME = "o.c.u.g.m.j.e.JaxRSEvent";

@Label ( "Resource Method" )
public String method;

@Label ( "Media type" )
public String mediaType;

@Label ( "Java method" )
public String methodFrameName;

@Label ( "Path" )
public String path;

@Label ( "Request length" )
@DataAmount
public int length;

@Label ( "Response length" )
@DataAmount
public int responseLength;

@Label ( "Status" )
public int status;
}

0 comments on commit 455bdda

Please sign in to comment.