All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.bootstrap.StartupException Maven / Gradle / Ivy

There is a newer version: 8.13.4
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.bootstrap;

import org.elasticsearch.common.inject.CreationException;
import org.elasticsearch.common.inject.spi.Message;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.function.Consumer;

/**
 * Wraps an exception in a special way that it gets formatted
 * "reasonably". This means limits on stacktrace frames and
 * cleanup for guice, and some guidance about consulting full
 * logs for the whole exception.
 */
// TODO: remove this when guice is removed, and exceptions are cleaned up
// this is horrible, but its what we must do
final class StartupException extends RuntimeException {

    /** maximum length of a stacktrace, before we truncate it */
    static final int STACKTRACE_LIMIT = 30;
    /** all lines from this package are RLE-compressed */
    static final String GUICE_PACKAGE = "org.elasticsearch.common.inject";

    /**
     * Create a new StartupException that will format {@code cause}
     * to the console on failure.
     */
    StartupException(Throwable cause) {
        super(cause);
    }

    /*
     * This logic actually prints the exception to the console, its
     * what is invoked by the JVM when we throw the exception from main()
     */
    @Override
    public void printStackTrace(PrintStream s) {
        printStackTrace(s::println);
    }

    @Override
    public void printStackTrace(PrintWriter s) {
        printStackTrace(s::println);
    }

    private void printStackTrace(Consumer consumer) {
        Throwable originalCause = getCause();
        Throwable cause = originalCause;
        if (cause instanceof CreationException) {
            cause = getFirstGuiceCause((CreationException) cause);
        }

        String message = cause.toString();
        consumer.accept(message);

        if (cause != null) {
            // walk to the root cause
            while (cause.getCause() != null) {
                cause = cause.getCause();
            }

            // print the root cause message, only if it differs!
            if (cause != originalCause && (message.equals(cause.toString()) == false)) {
                consumer.accept("Likely root cause: " + cause);
            }

            // print stacktrace of cause
            StackTraceElement stack[] = cause.getStackTrace();
            int linesWritten = 0;
            for (int i = 0; i < stack.length; i++) {
                if (linesWritten == STACKTRACE_LIMIT) {
                    consumer.accept("\t<<>>");
                    break;
                }
                String line = stack[i].toString();

                // skip past contiguous runs of this garbage:
                if (line.startsWith(GUICE_PACKAGE)) {
                    while (i + 1 < stack.length && stack[i + 1].toString().startsWith(GUICE_PACKAGE)) {
                        i++;
                    }
                    consumer.accept("\tat <<>>");
                    linesWritten++;
                    continue;
                }

                consumer.accept("\tat " + line);
                linesWritten++;
            }
        }
        // if its a guice exception, the whole thing really will not be in the log, its megabytes.
        // refer to the hack in bootstrap, where we don't log it
        if (originalCause instanceof CreationException == false) {
            final String basePath = System.getProperty("es.logs.base_path");
            // It's possible to fail before logging has been configured, in which case there's no point
            // suggested that the user look in the log file.
            if (basePath != null) {
                final String logPath = System.getProperty("es.logs.base_path")
                    + System.getProperty("file.separator")
                    + System.getProperty("es.logs.cluster_name")
                    + ".log";

                consumer.accept("For complete error details, refer to the log at " + logPath);
            }
        }
    }

    /**
     * Returns first cause from a guice error (it can have multiple).
     */
    static Throwable getFirstGuiceCause(CreationException guice) {
        for (Message message : guice.getErrorMessages()) {
            Throwable cause = message.getCause();
            if (cause != null) {
                return cause;
            }
        }
        return guice; // we tried
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy