net.logstash.logback.stacktrace.StackHasher Maven / Gradle / Ivy
Show all versions of logstash-logback-encoder Show documentation
/*
* Copyright 2013-2022 the original author or authors.
*
* 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.logstash.logback.stacktrace;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Utility class that generates a hash from any Java {@link Throwable error}
*
* @author Pierre Smeyers
*/
public class StackHasher {
private final StackElementFilter filter;
/**
* Constructs a {@link StackHasher} with the given filter.
*
* @param filter filter
*/
public StackHasher(StackElementFilter filter) {
this.filter = filter;
}
/**
* Constructs a {@link StackHasher} using {@link StackElementFilter#withSourceInfo()} filter
*/
public StackHasher() {
this(StackElementFilter.withSourceInfo());
}
/**
* Generates a Hexadecimal hash for the given error stack.
*
* Two errors with the same stack hash are most probably same errors.
*
* @param error the error to generate a hash from
* @return the generated hexadecimal hash
*/
public String hexHash(Throwable error) {
// compute topmost error hash, but don't queue the complete hashes chain
return toHex(hash(error, null));
}
/**
* Generates and returns Hexadecimal hashes for the error stack and each ancestor {@link Throwable#getCause() cause}.
*
* The first queue element is the stack hash for the topmost error, the next one (if any) is it's direct
* {@link Throwable#getCause() cause} hash, and so on...
*
* @param error the error to generate a hash from
* @return a Dequeue with hashes
*/
public Deque hexHashes(Throwable error) {
Deque hexHashes = new ArrayDeque();
hash(error, hexHashes);
return hexHashes;
}
/**
* Generates a hash (int) of the given error stack.
*
* Two errors with the same stack hash are most probably same errors.
*
* @param error the error to generate a hash from
* @param hexHashes
* @return the generated hexadecimal hash
*/
int hash(Throwable error, Deque hexHashes) {
int hash = 0;
// compute parent error hash
if (error.getCause() != null && error.getCause() != error) {
// has parent error
hash = hash(error.getCause(), hexHashes);
}
// then this error hash
// hash error classname
hash = 31 * hash + error.getClass().getName().hashCode();
// hash stacktrace
for (StackTraceElement element : error.getStackTrace()) {
if (filter.accept(element)) {
hash = 31 * hash + hash(element);
}
}
// push hexadecimal representation of hash
if (hexHashes != null) {
hexHashes.push(toHex(hash));
}
return hash;
}
String toHex(int hash) {
return String.format("%08x", hash);
}
int hash(StackTraceElement element) {
int result = element.getClassName().hashCode();
result = 31 * result + element.getMethodName().hashCode();
// let's assume filename is not necessary
result = 31 * result + element.getLineNumber();
return result;
}
}