Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add special handler to allow logger messages during shutdown #1387

Merged
merged 1 commit into from
Nov 10, 2015

Conversation

drcrallen
Copy link
Contributor

This gets rid of those pesky FATAL Unable to register shutdown hook because JVM is shutting down. messages.

Previously the shutdown hooks fire essentially at random. This was causing logging messages to regularly be lost during the shutdown cycle if the log4j shutdown hook was fired before some of the ones that use logging in their shutdown messages.

This patch (with the appropriate server setting) causes the logger shutdown to fire as the last lifecycle.stop() item.

Omitting the server property simply reverts to the prior behavior of regularly discarding logger messages during shutdown.

@drcrallen
Copy link
Contributor Author

Example without this patch:

2015-05-22T23:13:46,153 INFO [main] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking start method[public void io.druid.server.coordination.AbstractDataSegmentAnnouncer.start()] on object[io.druid.server.coordination.BatchDataSegmentAnnouncer@7df01c0f].
2015-05-22T23:13:46,153 INFO [main] io.druid.server.coordination.AbstractDataSegmentAnnouncer - Announcing self[DruidServerMetadata{name='localhost:8081', host='localhost:8081', maxSize=10000000000, tier='_default_tier', type='historical', priority='0'}] at [/druid/announcements/localhost:8081]
2015-05-22T23:13:46,670 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle - Running shutdown hook
2015-05-22 23:13:46,703 FATAL Unable to register shutdown hook because JVM is shutting down.

Example WITH this patch:

2015-05-22T23:14:46,373 INFO [main] io.druid.server.coordination.AbstractDataSegmentAnnouncer - Announcing self[DruidServerMetadata{name='localhost:8081', host='localhost:8081', maxSize=10000000000, tier='_default_tier', type='historical', priority='0'}] at [/druid/announcements/localhost:8081]
2015-05-22T23:14:48,511 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle - Running shutdown hook
2015-05-22T23:14:48,514 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void io.druid.server.coordination.AbstractDataSegmentAnnouncer.stop()] on object[io.druid.server.coordination.BatchDataSegmentAnnouncer@18a7811e].
2015-05-22T23:14:48,514 INFO [Thread-52] io.druid.server.coordination.AbstractDataSegmentAnnouncer - Stopping class io.druid.server.coordination.BatchDataSegmentAnnouncer with config[io.druid.server.initialization.ZkPathsConfig@58d3f4be]
2015-05-22T23:14:48,514 INFO [Thread-52] io.druid.curator.announcement.Announcer - unannouncing [/druid/announcements/localhost:8081]
2015-05-22T23:14:48,535 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void io.druid.server.coordination.BaseZkCoordinator.stop()] on object[io.druid.server.coordination.ZkCoordinator@86e795a].
2015-05-22T23:14:48,535 INFO [Thread-52] io.druid.server.coordination.ZkCoordinator - Stopping ZkCoordinator for [DruidServerMetadata{name='localhost:8081', host='localhost:8081', maxSize=10000000000, tier='_default_tier', type='historical', priority='0'}]
2015-05-22T23:14:48,538 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void io.druid.curator.announcement.Announcer.stop()] on object[io.druid.curator.announcement.Announcer@1eac5edf].
2015-05-22T23:14:48,539 INFO [Thread-52] io.druid.curator.announcement.Announcer - unannouncing [/druid/segments/localhost:8081/localhost:8081_historical__default_tier_2015-05-22T23:14:46.300Z_3f633ec82ac044cf87bfbd06f452026d0]
2015-05-22T23:14:48,540 INFO [Thread-52] io.druid.curator.CuratorModule - Stopping Curator
2015-05-22T23:14:48,545 INFO [Thread-52] org.apache.zookeeper.ZooKeeper - Session: 0x14d2f23309e0112 closed
2015-05-22T23:14:48,545 INFO [main-EventThread] org.apache.zookeeper.ClientCnxn - EventThread shut down
2015-05-22T23:14:48,558 INFO [Thread-52] org.eclipse.jetty.server.ServerConnector - Stopped ServerConnector@6a3cb917{HTTP/1.1}{0.0.0.0:8081}
2015-05-22T23:14:48,560 INFO [Thread-52] org.eclipse.jetty.server.handler.ContextHandler - Stopped o.e.j.s.ServletContextHandler@3441ba3a{/,null,UNAVAILABLE}
2015-05-22T23:14:48,566 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void com.metamx.metrics.MonitorScheduler.stop()] on object[com.metamx.metrics.MonitorScheduler@44b641c4].
2015-05-22T23:14:48,567 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void com.metamx.emitter.service.ServiceEmitter.close() throws java.io.IOException] on object[com.metamx.emitter.service.ServiceEmitter@2fc64742].
2015-05-22T23:14:48,567 INFO [Thread-52] com.metamx.emitter.core.LoggingEmitter - Close: started [false]
2015-05-22T23:14:48,567 INFO [Thread-52] com.metamx.common.lifecycle.Lifecycle$AnnotationBasedHandler - Invoking stop method[public void com.metamx.emitter.core.LoggingEmitter.close() throws java.io.IOException] on object[com.metamx.emitter.core.LoggingEmitter@3b53bb3b].

@gianm
Copy link
Contributor

gianm commented May 23, 2015

Bummer about the shutdown hooks.

Some questions:

  • Does the code actually get called? It doesn't look like anything is injecting the QuietLoggerShutdown and I dunno if it will actually get instantiated.
  • Is it possible to do something useful without needing a property? If not, how about emitting a warning on startup if the property isn't there, so people know they have a less than perfect setup?
  • Is the dependency worth it or is it doing something really simple that we could just do ourselves?

@drcrallen
Copy link
Contributor Author

@gianm : The dependency is exactly one java class https://github.com/DjDCH/Log4j-StaticShutdown/blob/master/src/main/java/com/djdch/log4j/StaticShutdownCallbackRegistry.java that we would pretty much have to copy to get the functionality. It is MIT license so direct copy is probably a no-go.

The CLI classes pickup ManageLifecycle automagically.

This will revert to the prior behavior if the property is missing.

@cheddar
Copy link
Contributor

cheddar commented May 27, 2015

Looking at what that class does, it basically just extends Log4j's ShutdownCallbackRegistry. It's pretty difficult to do programmatic stuff to adjust the configuration of the log4j subsystem when you use properties files to initialize it. We essentially need to set the system property before the log4j system is initialized.

I believe it is initialized by the first call to LoggerFactory.getLogger() in com.metamx.common.logging.Logger.

So, if we were to actually add a static initializer there to set the system property for us, we would likely be able to register our own shutdown handler instead of having it use the internal one.

I would then recommend that we create our own ShutdownCallbackRegistry that

  1. Registers with the normal JVM shutdown hook
  2. On start() removes the JVM shutdown hook
  3. On close(), if start() was called, shuts things down, if start() was not called, is a noop.

@drcrallen
Copy link
Contributor Author

@cheddar : Doing such a thing in the Logger would also be a multi-system intrusion of log4j instead of slf4j abstraction.

We cannot rely on the JVM shutdown hook because they are fired essentially randomly. We have to be able to specify that the logger shutdown hook runs after the Lifecycle shutdown, which is not the case if both are simply shutdown hooks (unless you know some magic you would like to share :) )

@drcrallen drcrallen force-pushed the enableShutdownLogging branch 3 times, most recently from 4333af4 to 9d7ba77 Compare June 5, 2015 18:11
@drcrallen
Copy link
Contributor Author

@cheddar : Modified

}
};
shutdownCallbacks.add(cancellable);
if (!isStarted()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me why this means that we are shutting down in the middle of registering. Couldn't it just not have been started in the first place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method has a !isStarted check at the top. If it is started at the top but not started here, it is because of a shutdown in progress.

@cheddar
Copy link
Contributor

cheddar commented Jun 12, 2015

Is it at all possible to add a check somewhere that can notice if the static property setting stuff was too late and warn/error about it?

"shutdownCallbackRegistry"
);
shutdownCallbackRegistryField.setAccessible(true);
final Log4jShutdown log4jShutdown = (Log4jShutdown) shutdownCallbackRegistryField.get(LogManager.getFactory());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need reflection to reach in and call the shutdowner? Can't we just get it injected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log4j does its own instantiation based on the system property and does not inject through guice. This was the only way at the time I could find of grabbing the log4j instance. Seems like a bug in log4j2 imho (unless I'm missing something)

@drcrallen drcrallen added this to the 0.9 milestone Sep 2, 2015
@drcrallen
Copy link
Contributor Author

@cheddar There is now a check in the configure step via class cast and a warning if the class cast fails.

@gianm
Copy link
Contributor

gianm commented Oct 27, 2015

👍

@drcrallen
Copy link
Contributor Author

@gianm / @cheddar updated to 2.4.1 to eliminate the need for reflection

.to(Log4jShutterDowner.class)
.asEagerSingleton();
}
catch (ClassNotFoundException | ClassCastException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be catching NoClassDefFoundError too? I think that would pop up if the log4j stuff (like org.apache.logging.log4j.core.impl.Log4jContextFactory) isn't on the classpath.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added LinkageError

* Adds a special PropertyChecker interface which is ONLY for setting string properties at the very start of psvm
@gianm
Copy link
Contributor

gianm commented Oct 27, 2015

still 👍

xvrl added a commit that referenced this pull request Nov 10, 2015
Add special handler to allow logger messages during shutdown
@xvrl xvrl merged commit a57cbfd into apache:master Nov 10, 2015
@xvrl xvrl deleted the enableShutdownLogging branch November 10, 2015 01:20
@gianm gianm modified the milestones: 0.8.3, 0.9.0 Dec 1, 2015
This was referenced Dec 1, 2015
seoeun25 pushed a commit to seoeun25/incubator-druid that referenced this pull request Jan 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants