/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.jmx;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import static java.util.Arrays.asList;
public final class ExceptionStats implements JmxStats<ExceptionStats> {
public static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
private Class<? extends Throwable> exceptionClass;
private int count;
private long lastExceptionTimestamp;
private ExceptionSummary summary;
private ExceptionDetails details;
private ExceptionStats() {
summary = new ExceptionSummary();
assert (details = new ExceptionDetails()) != null;
assert (summary = null) == null;
}
public static ExceptionStats create() {
return new ExceptionStats();
}
public ExceptionStats withStoreStackTrace(boolean store) {
if (store) {
details = new ExceptionDetails();
summary = null;
} else {
details = null;
summary = new ExceptionSummary();
}
return this;
}
public void recordException(Throwable throwable, Object context) {
this.count++;
this.exceptionClass = throwable != null ? throwable.getClass() : null;
this.lastExceptionTimestamp = System.currentTimeMillis();
if (details != null) {
details.throwable = throwable;
details.context = context;
}
}
public void recordException(Throwable throwable) {
recordException(throwable, null);
}
public void resetStats() {
this.exceptionClass = null;
this.count = 0;
this.lastExceptionTimestamp = 0;
if (details != null) {
details.throwable = null;
details.context = null;
}
}
@Override
public void add(ExceptionStats another) {
this.count += another.count;
if (another.lastExceptionTimestamp >= this.lastExceptionTimestamp) {
this.exceptionClass = another.exceptionClass;
this.lastExceptionTimestamp = another.lastExceptionTimestamp;
if (another.details != null) {
if (this.details == null) {
details = new ExceptionDetails();
}
this.details.throwable = another.details.throwable;
this.details.context = another.details.context;
}
}
}
@JmxAttribute
public int getTotal() {
return count;
}
@JmxAttribute(optional = true)
public String getLastType() {
return exceptionClass != null ? exceptionClass.toString() : null;
}
@JmxAttribute(optional = true)
public String getLastTimestamp() {
return lastExceptionTimestamp != 0 ? TIMESTAMP_FORMAT.format(new Date(lastExceptionTimestamp)) : null;
}
public Throwable getLastException() {
return details != null ? details.throwable : null;
}
@JmxAttribute(optional = true)
public String getLastMessage() {
if (details == null) {
return null;
}
if (details.throwable == null) {
return null;
}
return details.throwable.getMessage();
}
@JmxAttribute(name = "")
public ExceptionSummary getSummary() {
return summary;
}
@JmxAttribute(name = "")
public ExceptionDetails getDetails() {
return details;
}
@Override
public String toString() {
String last = "";
if (exceptionClass != null) {
last = "; " + exceptionClass.getSimpleName();
last += " @ " + getLastTimestamp();
}
return Integer.toString(count) + last;
}
public final class ExceptionDetails {
private Throwable throwable;
private Object context;
@JmxAttribute
public Object getLastContext() {
return context;
}
@JmxAttribute
public List<String> getLastStackTrace() {
if (throwable != null) {
return asList(MBeanFormat.formatException(throwable));
} else {
return null;
}
}
@JmxAttribute
public String getSummary() {
if (count == 0) return "";
StringBuilder summary = new StringBuilder("Total: " + count);
if (throwable != null) {
summary.append("\n\nStack Trace: ");
summary.append(MBeanFormat.formatExceptionLine(throwable).trim());
}
if (context != null) {
summary.append("\n\nContext: ");
summary.append(context.toString());
}
return summary.toString();
}
}
public final class ExceptionSummary {
@JmxAttribute
public String getLast() {
return exceptionClass != null ? exceptionClass.getName() : null;
}
}
}