/*
* Copyright 2014 Groupon, Inc
* Copyright 2014 The Billing Project, LLC
*
* The Billing Project 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.killbill.billing.server.filters;
import java.util.List;
import org.killbill.billing.jaxrs.json.ProfilingDataJson;
import org.killbill.billing.util.jackson.ObjectMapper;
import org.killbill.commons.profiling.Profiling;
import org.killbill.commons.profiling.ProfilingData;
import org.killbill.commons.profiling.ProfilingFeature.ProfilingFeatureType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.inject.Singleton;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
@Singleton
public class ProfilingContainerResponseFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static final Logger log = LoggerFactory.getLogger(ProfilingContainerResponseFilter.class);
private static final String PROFILING_HEADER_REQ = "X-Killbill-Profiling-Req";
private static final String PROFILING_HEADER_RESP = "X-Killbill-Profiling-Resp";
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
}
@Override
public ContainerRequest filter(final ContainerRequest request) {
final List<String> profilingHeaderRequests = request.getRequestHeader(PROFILING_HEADER_REQ);
final String profilingHeaderRequest = (profilingHeaderRequests == null || profilingHeaderRequests.isEmpty()) ? null : profilingHeaderRequests.get(0);
if (profilingHeaderRequest != null) {
try {
Profiling.setPerThreadProfilingData(profilingHeaderRequest);
// If we need to profile JAXRS let's do it...
final ProfilingData profilingData = Profiling.getPerThreadProfilingData();
if (profilingData.getProfileFeature().isProfilingJAXRS()) {
profilingData.addStart(ProfilingFeatureType.JAXRS, request.getPath());
}
} catch (IllegalArgumentException e) {
log.info("Profiling data output {} is not supported, profiling NOT enabled", profilingHeaderRequest);
}
}
return request;
}
@Override
public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response) {
try {
final ProfilingData rawData = Profiling.getPerThreadProfilingData();
if (rawData != null) {
if (rawData.getProfileFeature().isProfilingJAXRS()) {
rawData.addEnd(ProfilingFeatureType.JAXRS, request.getPath());
}
final ProfilingDataJson profilingData = new ProfilingDataJson(rawData);
final String value;
try {
value = mapper.writeValueAsString(profilingData);
response.getHttpHeaders().add(PROFILING_HEADER_RESP, value);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
} finally {
Profiling.resetPerThreadProfilingData();
}
return response;
}
}