use of io.cdap.cdap.common.logging.common.UncaughtExceptionHandler in project cdap by caskdata.
the class DaemonMain method doMain.
/**
* The main method. It simply call methods in the same sequence
* as if the program is started by jsvc.
*/
protected void doMain(final String[] args) throws Exception {
try {
init(args);
} catch (Throwable t) {
LOG.error("Exception raised when calling init", t);
try {
destroy();
} catch (Throwable t2) {
LOG.error("Exception raised when calling destroy", t);
t.addSuppressed(t2);
}
// Throw to terminate the main thread
throw t;
}
CountDownLatch shutdownLatch = new CountDownLatch(1);
AtomicBoolean terminated = new AtomicBoolean();
Runnable terminateRunnable = () -> {
if (!terminated.compareAndSet(false, true)) {
return;
}
try {
try {
DaemonMain.this.stop();
} finally {
try {
DaemonMain.this.destroy();
} finally {
shutdownLatch.countDown();
}
}
} catch (Throwable t) {
LOG.error("Exception when shutting down: " + t.getMessage(), t);
}
};
Runtime.getRuntime().addShutdownHook(new Thread(terminateRunnable));
try {
start();
} catch (Throwable t) {
// Throw to terminate the main thread
LOG.error("Exception raised when calling start", t);
terminateRunnable.run();
throw t;
}
// Set uncaught exception handler after startup, this is so that if startup throws exception then we
// want it to be logged as error (the handler logs it as debug)
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
shutdownLatch.await();
}
use of io.cdap.cdap.common.logging.common.UncaughtExceptionHandler in project cdap by caskdata.
the class SparkContainerLauncher method launch.
/**
* Launches the given main class. The main class will be loaded through the {@link SparkContainerClassLoader}.
*
* @param mainClassName the main class to launch
* @param args arguments for the main class
* @param removeMainClass whether to remove the jar for the main class from the classloader
* @param masterEnvName name of the MasterEnvironment used to submit the Spark job. This will be used to setup
* bindings for service discovery and other CDAP capabilities. If null, the default Hadoop implementations will
* be used.
*/
public static void launch(String mainClassName, String[] args, boolean removeMainClass, @Nullable String masterEnvName) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Set<URL> urls = ClassLoaders.getClassLoaderURLs(systemClassLoader, new LinkedHashSet<URL>());
// method call from the container launch script.
if (removeMainClass) {
urls.remove(getURLByClass(systemClassLoader, mainClassName));
}
// Remove the first scala from the set of classpath. This ensure the one from Spark is used for spark
removeNonSparkJar(systemClassLoader, "scala.language", urls);
// Remove the first jar containing LZBlockInputStream from the set of classpath.
// The one from Kafka is not compatible with Spark
removeNonSparkJar(systemClassLoader, "net.jpountz.lz4.LZ4BlockInputStream", urls);
// First create a FilterClassLoader that only loads JVM and kafka classes from the system classloader
// This is to isolate the scala library from children
ClassLoader parentClassLoader = new FilterClassLoader(systemClassLoader, KAFKA_FILTER);
boolean rewriteCheckpointTempFileName = Boolean.parseBoolean(System.getProperty(SparkRuntimeUtils.STREAMING_CHECKPOINT_REWRITE_ENABLED, "false"));
// Creates the SparkRunnerClassLoader for class rewriting and it will be used for the rest of the execution.
// Use the extension classloader as the parent instead of the system classloader because
// Spark classes are in the system classloader which we want to rewrite.
ClassLoader classLoader = new SparkContainerClassLoader(urls.toArray(new URL[0]), parentClassLoader, rewriteCheckpointTempFileName);
// Sets the context classloader and launch the actual Spark main class.
Thread.currentThread().setContextClassLoader(classLoader);
// Create SLF4J logger from the context classloader. It has to be created from that classloader in order
// for logs in this class to be in the same context as the one used in Spark.
Object logger = createLogger(classLoader);
// Install the JUL to SLF4J Bridge
try {
classLoader.loadClass(SLF4JBridgeHandler.class.getName()).getDeclaredMethod("install").invoke(null);
} catch (Exception e) {
// Log the error and continue
log(logger, "warn", "Failed to invoke SLF4JBridgeHandler.install() required for jul-to-slf4j bridge", e);
}
// Get the SparkRuntimeContext to initialize all necessary services and logging context
// Need to do it using the SparkRunnerClassLoader through reflection.
Class<?> sparkRuntimeContextProviderClass = classLoader.loadClass(SparkRuntimeContextProvider.class.getName());
if (masterEnvName != null) {
sparkRuntimeContextProviderClass.getMethod("setMasterEnvName", String.class).invoke(null, masterEnvName);
}
Object sparkRuntimeContext = sparkRuntimeContextProviderClass.getMethod("get").invoke(null);
if (sparkRuntimeContext instanceof Closeable) {
System.setSecurityManager(new SparkRuntimeSecurityManager((Closeable) sparkRuntimeContext));
}
try {
// in the PythonRunner/PythonWorkerFactory via SparkClassRewriter.
if (!isPySpark()) {
// Invoke StandardOutErrorRedirector.redirectToLogger()
classLoader.loadClass(StandardOutErrorRedirector.class.getName()).getDeclaredMethod("redirectToLogger", String.class).invoke(null, mainClassName);
}
// which causes executor logs attempt to write to driver log directory
if (System.getProperty("spark.executorEnv.CDAP_LOG_DIR") != null) {
System.setProperty("spark.executorEnv.CDAP_LOG_DIR", "<LOG_DIR>");
}
// Optionally starts Py4j Gateway server in the executor container
Runnable stopGatewayServer = startGatewayServerIfNeeded(classLoader, logger);
try {
log(logger, "info", "Launch main class {}.main({})", mainClassName, Arrays.toString(args));
classLoader.loadClass(mainClassName).getMethod("main", String[].class).invoke(null, new Object[] { args });
log(logger, "info", "Main method returned {}", mainClassName);
} finally {
stopGatewayServer.run();
}
} catch (Throwable t) {
// LOG the exception since this exception will be propagated back to JVM
// and kill the main thread (hence the JVM process).
// If we don't log it here as ERROR, it will be logged by UncaughtExceptionHandler as DEBUG level
log(logger, "error", "Exception raised when calling {}.main(String[]) method", mainClassName, t);
throw t;
} finally {
if (sparkRuntimeContext instanceof Closeable) {
Closeables.closeQuietly((Closeable) sparkRuntimeContext);
}
}
}
use of io.cdap.cdap.common.logging.common.UncaughtExceptionHandler in project cdap by caskdata.
the class DefaultRuntimeJob method run.
@Override
public void run(RuntimeJobEnvironment runtimeJobEnv) throws Exception {
// Setup process wide settings
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
// Get Program Options
ProgramOptions programOpts = readJsonFile(new File(DistributedProgramRunner.PROGRAM_OPTIONS_FILE_NAME), ProgramOptions.class);
ProgramRunId programRunId = programOpts.getProgramId().run(ProgramRunners.getRunId(programOpts));
ProgramId programId = programRunId.getParent();
Arguments systemArgs = programOpts.getArguments();
// Setup logging context for the program
LoggingContextAccessor.setLoggingContext(LoggingContextHelper.getLoggingContextWithRunId(programRunId, systemArgs.asMap()));
// Get the cluster launch type
Cluster cluster = GSON.fromJson(systemArgs.getOption(ProgramOptionConstants.CLUSTER), Cluster.class);
// Get App spec
ApplicationSpecification appSpec = readJsonFile(new File(DistributedProgramRunner.APP_SPEC_FILE_NAME), ApplicationSpecification.class);
ProgramDescriptor programDescriptor = new ProgramDescriptor(programId, appSpec);
// Create injector and get program runner
Injector injector = Guice.createInjector(createModules(runtimeJobEnv, createCConf(runtimeJobEnv, programOpts), programRunId, programOpts));
CConfiguration cConf = injector.getInstance(CConfiguration.class);
// Initialize log appender
LogAppenderInitializer logAppenderInitializer = injector.getInstance(LogAppenderInitializer.class);
logAppenderInitializer.initialize();
SystemArguments.setLogLevel(programOpts.getUserArguments(), logAppenderInitializer);
ProxySelector oldProxySelector = ProxySelector.getDefault();
RuntimeMonitors.setupMonitoring(injector, programOpts);
Deque<Service> coreServices = createCoreServices(injector, systemArgs, cluster);
startCoreServices(coreServices);
// regenerate app spec
ConfiguratorFactory configuratorFactory = injector.getInstance(ConfiguratorFactory.class);
try {
Map<String, String> systemArguments = new HashMap<>(programOpts.getArguments().asMap());
File pluginDir = new File(programOpts.getArguments().getOption(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR));
// create a directory to store plugin artifacts for the regeneration of app spec to fetch plugin artifacts
DirUtils.mkdirs(pluginDir);
if (!programOpts.getArguments().hasOption(ProgramOptionConstants.PLUGIN_DIR)) {
systemArguments.put(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR);
}
// remember the file names in the artifact folder before app regeneration
List<String> pluginFiles = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
ApplicationSpecification generatedAppSpec = regenerateAppSpec(systemArguments, programOpts.getUserArguments().asMap(), programId, appSpec, programDescriptor, configuratorFactory);
appSpec = generatedAppSpec != null ? generatedAppSpec : appSpec;
programDescriptor = new ProgramDescriptor(programDescriptor.getProgramId(), appSpec);
List<String> pluginFilesAfter = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
if (pluginFilesAfter.isEmpty()) {
systemArguments.remove(ProgramOptionConstants.PLUGIN_DIR);
}
// recreate it from the folders
if (!pluginFiles.equals(pluginFilesAfter)) {
systemArguments.remove(ProgramOptionConstants.PLUGIN_ARCHIVE);
}
// update program options
programOpts = new SimpleProgramOptions(programOpts.getProgramId(), new BasicArguments(systemArguments), programOpts.getUserArguments(), programOpts.isDebug());
} catch (Exception e) {
LOG.warn("Failed to regenerate the app spec for program {}, using the existing app spec", programId, e);
}
ProgramStateWriter programStateWriter = injector.getInstance(ProgramStateWriter.class);
RuntimeClientService runtimeClientService = injector.getInstance(RuntimeClientService.class);
CompletableFuture<ProgramController.State> programCompletion = new CompletableFuture<>();
try {
ProgramRunner programRunner = injector.getInstance(ProgramRunnerFactory.class).create(programId.getType());
// Create and run the program. The program files should be present in current working directory.
try (Program program = createProgram(cConf, programRunner, programDescriptor, programOpts)) {
ProgramController controller = programRunner.run(program, programOpts);
controllerFuture.complete(controller);
runtimeClientService.onProgramStopRequested(controller::stop);
controller.addListener(new AbstractListener() {
@Override
public void completed() {
programCompletion.complete(ProgramController.State.COMPLETED);
}
@Override
public void killed() {
// Write an extra state to make sure there is always a terminal state even
// if the program application run failed to write out the state.
programStateWriter.killed(programRunId);
programCompletion.complete(ProgramController.State.KILLED);
}
@Override
public void error(Throwable cause) {
// Write an extra state to make sure there is always a terminal state even
// if the program application run failed to write out the state.
programStateWriter.error(programRunId, cause);
programCompletion.completeExceptionally(cause);
}
}, Threads.SAME_THREAD_EXECUTOR);
if (stopRequested) {
controller.stop();
}
// Block on the completion
programCompletion.get();
} finally {
if (programRunner instanceof Closeable) {
Closeables.closeQuietly((Closeable) programRunner);
}
}
} catch (Throwable t) {
controllerFuture.completeExceptionally(t);
if (!programCompletion.isDone()) {
// We log here so that the logs would still send back to the program logs collection.
// Only log if the program completion is not done.
// Otherwise the program runner itself should have logged the error.
LOG.error("Failed to execute program {}", programRunId, t);
// If the program completion is not done, then this exception
// is due to systematic failure in which fail to run the program.
// We write out an extra error state for the program to make sure the program state get transited.
programStateWriter.error(programRunId, t);
}
throw t;
} finally {
stopCoreServices(coreServices, logAppenderInitializer);
ProxySelector.setDefault(oldProxySelector);
Authenticator.setDefault(null);
runCompletedLatch.countDown();
}
}
use of io.cdap.cdap.common.logging.common.UncaughtExceptionHandler in project cdap by caskdata.
the class RemoteExecutionJobMain method main.
public static void main(String[] args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
new RemoteExecutionJobMain().doMain(args);
}
Aggregations