/*
* Copyright 2008-2017 by Emeric Vernat
*
* This file is part of Java Melody.
*
* 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 net.bull.javamelody;
import java.io.Serializable;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
/**
* Objet correspondant à une erreur dans filtre http ou dans logs à un instant t, avec son message, sa stackTrace
* éventuelle et son utilisateur courant s'il est défini.
* @author Emeric Vernat
*/
class CounterError implements Serializable {
static final String REQUEST_KEY = "javamelody.request";
private static final long serialVersionUID = 5690702786722045646L;
@SuppressWarnings("all")
private static final ThreadLocal<HttpServletRequest> HTTP_SERVLET_REQUEST_CONTEXT = new ThreadLocal<HttpServletRequest>();
/**
* Max size of error message.
*/
private static final int MESSAGE_MAX_LENGTH = 1000;
/**
* Max size of error stack-trace.
*/
private static final int STACKTRACE_MAX_LENGTH = 50000;
private final long time;
private final String remoteUser;
private final String httpRequest;
private final String message;
private final String stackTrace;
CounterError(String message, String stackTrace) {
super();
assert message != null;
this.time = System.currentTimeMillis();
if (message.length() > MESSAGE_MAX_LENGTH) {
// avoid possible memory errors as javamelody store 100 errors in memory
this.message = message.substring(0, MESSAGE_MAX_LENGTH);
} else {
this.message = message;
}
if (stackTrace != null && stackTrace.length() > STACKTRACE_MAX_LENGTH) {
this.stackTrace = stackTrace.substring(0, STACKTRACE_MAX_LENGTH);
} else {
this.stackTrace = stackTrace;
}
final HttpServletRequest currentRequest = getCurrentRequest();
if (currentRequest == null) {
this.remoteUser = null;
this.httpRequest = null;
} else {
// unbindRequest pour éviter StackOverflowError dans le cas où getRemoteUser()
// fait un log warn ou error. Par exemple, dans le cas d'un SSO comme
// com.pixelpark.seraph.SSOAuthenticator.getUser (cf issue 24).
unbindRequest();
try {
this.httpRequest = (String) currentRequest.getAttribute(REQUEST_KEY);
this.remoteUser = currentRequest.getRemoteUser();
} finally {
bindRequest(currentRequest);
}
}
}
/**
* Définit la requête http (peut être nulle) pour le thread courant.
* @param request HttpServletRequest
*/
static void bindRequest(HttpServletRequest request) {
if (request != null) {
HTTP_SERVLET_REQUEST_CONTEXT.set(request);
}
}
/**
* Retourne la requête http pour le thread courant ou null si elle n'a pas été définie.
* @return HttpServletRequest
*/
private static HttpServletRequest getCurrentRequest() {
return HTTP_SERVLET_REQUEST_CONTEXT.get();
}
/**
* Enlève le lien entre la requête http et le thread courant.
*/
static void unbindRequest() {
HTTP_SERVLET_REQUEST_CONTEXT.remove();
}
long getTime() {
return time;
}
Date getDate() {
return new Date(time);
}
String getRemoteUser() {
return remoteUser;
}
String getHttpRequest() {
return httpRequest;
}
String getMessage() {
return message;
}
String getStackTrace() {
return stackTrace;
}
/** {@inheritDoc} */
@Override
public String toString() {
return getClass().getSimpleName() + "[message=" + getMessage() + ']';
}
}