/** * We cannot presume that the default file name/location setting won't be changed by the user. * Therefore, we should be able to retrieve that info from the underlying logging mechanism * by iterating over appenders. */ private List<Path> getActiveLogFilePaths() { LoggerContextFactory factory = LogManager.getFactory(); ContextSelector selector = ((Log4jContextFactory) factory).getSelector(); List<Path> fileNameList = new ArrayList<>(); for (LoggerContext ctx : selector.getLoggerContexts()) { for (Appender appender : ctx.getConfiguration().getAppenders().values()) { String fileName = extractFileName(appender); if (fileName != null) { fileNameList.add(Paths.get(fileName)); } } } return fileNameList; }
private void initializeJndi(final String location) throws UnavailableException { URI configLocation = null; if (location != null) { try { configLocation = new URI(location); } catch (final Exception e) { this.servletContext.log("Unable to convert configuration location [" + location + "] to a URI!", e); } } if (this.name == null) { throw new UnavailableException("A log4jContextName context parameter is required"); } LoggerContext loggerContext; final LoggerContextFactory factory = LogManager.getFactory(); if (factory instanceof Log4jContextFactory) { final ContextSelector selector = ((Log4jContextFactory) factory).getSelector(); if (selector instanceof NamedContextSelector) { this.selector = (NamedContextSelector) selector; loggerContext = this.selector.locateContext(this.name, this.servletContext, configLocation); ContextAnchor.THREAD_CONTEXT.set(loggerContext); if (loggerContext.getStatus() == LoggerContext.Status.INITIALIZED) { loggerContext.start(); } ContextAnchor.THREAD_CONTEXT.remove(); } else { this.servletContext.log("Potential problem: Selector is not an instance of NamedContextSelector."); return; } } else { this.servletContext.log("Potential problem: Factory is not an instance of Log4jContextFactory."); return; } this.loggerContext = loggerContext; this.servletContext.log("Created logger context for [" + this.name + "] using [" + loggerContext.getClass().getClassLoader() + "]."); }
/** * Creates MBeans to instrument the specified selector and other classes in * the log4j class hierarchy and registers the MBeans in the platform MBean * server so they can be accessed by remote clients. * * @param selector * starting point in the log4j class hierarchy * @throws JMException * if a problem occurs during registration */ public static void registerMBeans(final ContextSelector selector) throws JMException { // avoid creating Platform MBean Server if JMX disabled if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) { StatusLogger.getLogger().debug( "JMX disabled for log4j2. Not registering MBeans."); return; } final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); registerMBeans(selector, mbs); }
private static void registerContextSelector(final ContextSelector selector, final MBeanServer mbs, final Executor executor) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { final ContextSelectorAdmin mbean = new ContextSelectorAdmin(selector); mbs.registerMBean(mbean, mbean.getObjectName()); }
/** * Constructs a new {@code ContextSelectorAdmin}. * * @param selector the instrumented object */ public ContextSelectorAdmin(final ContextSelector selector) { super(); this.selector = Assert.isNotNull(selector, "ContextSelector"); try { objectName = new ObjectName(NAME); } catch (final Exception e) { throw new IllegalStateException(e); } }
private void initializeJndi(final String location) { final URI configLocation = getConfigURI(location); if (this.name == null) { throw new IllegalStateException("A log4jContextName context parameter is required"); } LoggerContext context; final LoggerContextFactory factory = LogManager.getFactory(); if (factory instanceof Log4jContextFactory) { final ContextSelector selector = ((Log4jContextFactory) factory).getSelector(); if (selector instanceof NamedContextSelector) { this.namedContextSelector = (NamedContextSelector) selector; context = this.namedContextSelector.locateContext(this.name, this.servletContext, configLocation); ContextAnchor.THREAD_CONTEXT.set(context); if (context.isInitialized()) { context.start(); } ContextAnchor.THREAD_CONTEXT.remove(); } else { LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector."); return; } } else { LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory."); return; } this.loggerContext = context; LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader()); }
/** * Returns the {@code ContextSelector} of the current {@code Log4jContextFactory}. * * @return the {@code ContextSelector} of the current {@code Log4jContextFactory} */ private static ContextSelector getContextSelector() { final LoggerContextFactory factory = LogManager.getFactory(); if (factory instanceof Log4jContextFactory) { final ContextSelector selector = ((Log4jContextFactory) factory).getSelector(); return selector; } return null; }
private static void registerContextSelector(final String contextName, final ContextSelector selector, final MBeanServer mbs, final Executor executor) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { final ContextSelectorAdmin mbean = new ContextSelectorAdmin(contextName, selector); register(mbs, mbean, mbean.getObjectName()); }
/** * Constructs a Log4jContextFactory using the provided ContextSelector and ShutdownRegistrationStrategy. * * @param selector the selector to use * @param shutdownCallbackRegistry the ShutdownRegistrationStrategy to use * @since 2.1 */ public Log4jContextFactory(final ContextSelector selector, final ShutdownCallbackRegistry shutdownCallbackRegistry) { this.selector = Objects.requireNonNull(selector, "No ContextSelector provided"); this.shutdownCallbackRegistry = Objects.requireNonNull(shutdownCallbackRegistry, "No ShutdownCallbackRegistry provided"); LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass()); initializeShutdownCallbackRegistry(); }
private static ContextSelector createContextSelector() { try { final ContextSelector selector = LoaderUtil.newCheckedInstanceOfProperty(Constants.LOG4J_CONTEXT_SELECTOR, ContextSelector.class); if (selector != null) { return selector; } } catch (final Exception e) { LOGGER.error("Unable to create custom ContextSelector. Falling back to default.", e); } return new ClassLoaderContextSelector(); }
public LoggerContextRule(final String configLocation, final Class<? extends ContextSelector> contextSelectorClass, final long shutdownTimeout, final TimeUnit shutdownTimeUnit) { this.configLocation = configLocation; this.contextSelectorClass = contextSelectorClass; this.shutdownTimeout = shutdownTimeout; this.shutdownTimeUnit = shutdownTimeUnit; }
@Test public void testShutdownCallbackRegistry() throws Exception { final LoggerContext context = ctx.getLoggerContext(); assertTrue("LoggerContext should be started", context.isStarted()); assertThat(Registry.CALLBACKS, hasSize(1)); Registry.shutdown(); assertTrue("LoggerContext should be stopped", context.isStopped()); assertThat(Registry.CALLBACKS, hasSize(0)); final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector(); assertThat(selector.getLoggerContexts(), not(hasItem(context))); }
/** * Creates MBeans to instrument the specified selector and other classes in * the log4j class hierarchy and registers the MBeans in the specified MBean * server so they can be accessed by remote clients. * * @param selector * starting point in the log4j class hierarchy * @param mbs * the MBean Server to register the instrumented objects in * @throws JMException * if a problem occurs during registration */ public static void registerMBeans(final ContextSelector selector, final MBeanServer mbs) throws JMException { if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) { StatusLogger.getLogger().debug( "JMX disabled for log4j2. Not registering MBeans."); return; } final Executor executor = Executors.newFixedThreadPool(1); registerStatusLogger(mbs, executor); registerContextSelector(selector, mbs, executor); final List<LoggerContext> contexts = selector.getLoggerContexts(); registerContexts(contexts, mbs, executor); for (final LoggerContext context : contexts) { context.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { if (!LoggerContext.PROPERTY_CONFIG.equals(evt .getPropertyName())) { return; } // first unregister the MBeans that instrument the // previous instrumented LoggerConfigs and Appenders unregisterLoggerConfigs(context, mbs); unregisterAppenders(context, mbs); // now provide instrumentation for the newly configured // LoggerConfigs and Appenders try { registerLoggerConfigs(context, mbs, executor); registerAppenders(context, mbs, executor); } catch (final Exception ex) { StatusLogger.getLogger().error( "Could not register mbeans", ex); } } }); } }
public static void reregisterMBeansAfterReconfigure(final MBeanServer mbs) { if (isJmxDisabled()) { LOGGER.debug("JMX disabled for Log4j2. Not registering MBeans."); return; } // now provide instrumentation for the newly configured // LoggerConfigs and Appenders try { final ContextSelector selector = getContextSelector(); if (selector == null) { LOGGER.debug("Could not register MBeans: no ContextSelector found."); return; } LOGGER.trace("Reregistering MBeans after reconfigure. Selector={}", selector); final List<LoggerContext> contexts = selector.getLoggerContexts(); int i = 0; for (final LoggerContext ctx : contexts) { LOGGER.trace("Reregistering context ({}/{}): '{}' {}", ++i, contexts.size(), ctx.getName(), ctx); // first unregister the context and all nested loggers, // appenders, statusLogger, contextSelector, ringbuffers... unregisterLoggerContext(ctx.getName(), mbs); final LoggerContextAdmin mbean = new LoggerContextAdmin(ctx, executor); register(mbs, mbean, mbean.getObjectName()); if (ctx instanceof AsyncLoggerContext) { final RingBufferAdmin rbmbean = ((AsyncLoggerContext) ctx).createRingBufferAdmin(); if (rbmbean.getBufferSize() > 0) { // don't register if Disruptor not started (DefaultConfiguration: config not found) register(mbs, rbmbean, rbmbean.getObjectName()); } } // register the status logger and the context selector // repeatedly // for each known context: if one context is unregistered, // these MBeans should still be available for the other // contexts. registerStatusLogger(ctx.getName(), mbs, executor); registerContextSelector(ctx.getName(), selector, mbs, executor); registerLoggerConfigs(ctx, mbs, executor); registerAppenders(ctx, mbs, executor); } } catch (final Exception ex) { LOGGER.error("Could not register mbeans", ex); } }
public XmlCompleteFileAppenderTest(final Class<ContextSelector> contextSelector) { this.loggerContextRule = new LoggerContextRule("XmlCompleteFileAppenderTest.xml", contextSelector); this.cleanFiles = new CleanFiles(logFile); this.ruleChain = RuleChain.outerRule(cleanFiles).around(loggerContextRule); }
public JsonCompleteFileAppenderTest(final Class<ContextSelector> contextSelector) { this.loggerContextRule = new LoggerContextRule("JsonCompleteFileAppenderTest.xml", contextSelector); this.cleanFiles = new CleanFiles(logFile); this.ruleChain = RuleChain.outerRule(cleanFiles).around(loggerContextRule); }
/** * Constructs a new {@code ContextSelectorAdmin}. * * @param contextName name of the LoggerContext under which to register this * ContextSelectorAdmin. Note that the ContextSelector may be * registered multiple times, once for each LoggerContext. In web * containers, each web application has its own LoggerContext and * by associating the ContextSelector with the LoggerContext, all * associated MBeans can be unloaded when the web application is * undeployed. * @param selector the instrumented object */ public ContextSelectorAdmin(final String contextName, final ContextSelector selector) { super(); this.selector = Objects.requireNonNull(selector, "ContextSelector"); try { final String mbeanName = String.format(PATTERN, Server.escape(contextName)); objectName = new ObjectName(mbeanName); } catch (final Exception e) { throw new IllegalStateException(e); } }
/** * Returns the ContextSelector. * @return The ContextSelector. */ public ContextSelector getSelector() { return selector; }
/** * Initializes this factory's ContextSelector with the specified selector. * @param selector the selector to use */ public Log4jContextFactory(final ContextSelector selector) { this(selector, createShutdownCallbackRegistry()); }
/** * Constructs a new LoggerContextRule for a given configuration file and a custom {@link ContextSelector} class. * * @param configLocation * path to configuration file * @param contextSelectorClass * custom ContextSelector class to use instead of default */ public LoggerContextRule(final String configLocation, final Class<? extends ContextSelector> contextSelectorClass) { this(configLocation, contextSelectorClass, AbstractLifeCycle.DEFAULT_STOP_TIMEOUT, AbstractLifeCycle.DEFAULT_STOP_TIMEUNIT); }